Reputation: 4643
I have read the pattern (defmulti multi (fn [t] (cond (seq? t) :seq (map? t) :map (vec? t) :vec ...
in lots of Clojure code here and there, which is basically a switch (if I add a type, I have to add a new clause) but more verbose. Is there not a way to say (defmethod seq, (defmethod vec (defmethod map..
etc ? It must be a very common thing to do. I'm aware that it's possible to manually define hierarchies, but what about common Clojure types like sequence, vector, map...would they have to be defined for each program which dispatched on type ? Please show me how I'm missing the point!
edit: ok I thought I could say (defmulti mymulti type)
then (defmethod clojure.lang.PeristantSomething...
etc, but that's clumsy as it refers to java classes, but I want to refer to some quality of the 'type' like whether it's sequential or associative
Upvotes: 1
Views: 345
Reputation: 19642
Dispatching on type works well for this:
user> (import '[clojure.lang Associative Sequential])
user> (defmulti foo type)
#'user/foo
user> (defmethod foo Associative [x] :map)
#<MultiFn clojure.lang.MultiFn@7e69a380>
user> (foo {:x 1})
:map
user> (foo ())
; fails, a list is not associative
user> (defmethod foo Sequential [x] :seq)
#<MultiFn clojure.lang.MultiFn@7e69a380>
user> (foo ())
:seq
user> (foo [])
; fails, a vector is both sequential and associative
user> (prefer-method foo Sequential Associative)
#<MultiFn clojure.lang.MultiFn@7e69a380>
user> (foo [])
:seq
Note that both Sequential and Associative are interfaces and not concrete classes.
Upvotes: 3