I made polymethod
s for fun a while back GitHub - johnmn3/dispacio: A predicate stack dispatch system for Clojure/Script
It’s similar to multimethods but let’s each method add its own dispatch function, rather than adding static values to be matched against the return value of a single dispatch function.
So you can use string?
or int?
or whatever predicate you want. Like:
(defp f-inc int? [x] (float (inc x)))
(defp f-inc string? [x] (float (inc (read-string x))))
Or even dispatch off of specs or whatever else you want:
(require '[clojure.spec.alpha :as s])
(s/def :animal/kind string?)
(s/def :animal/says string?)
(s/def :animal/common (s/keys :req [:animal/kind :animal/says]))
(s/def :dog/tail? boolean?)
(s/def :dog/breed string?)
(s/def :cat/breed string?)
(s/def :animal/dog (s/merge :animal/common
(s/keys :req [:dog/tail? :dog/breed])))
(s/def :animal/cat (s/merge :animal/common
(s/keys :req [:cat/breed])))
With specs defined, make your polymethods:
(defp make-noise #(s/valid? :animal/dog %)
[animal]
(println "A" (:dog/breed animal) "barks" (:animal/says animal)))
(defp make-noise #(s/valid? :animal/cat %)
[animal]
(println "A" (:cat/breed animal) "meows" (:animal/says animal)))
And then you can dispatch on valid data:
(make-noise
{:animal/kind "dog"
:animal/says "woof"
:dog/tail? true
:dog/breed "retriever"})
;#_=> A retriever barks woof
(make-noise
{:animal/kind "cat"
:animal/says "brrr"
:cat/breed "siamese"})
;#_=> A siamese meows brrr
Fun for when you want to experiment with different dispatch strategies based on the truthiness of arbitrary functions.