Polymorphic dispatch selects an implementation from an argument’s dispatch value, allowing one callable operation to support different behaviors. In Clojure, multimethods can dispatch on arbitrary values, while protocols primarily dispatch by type. section 15.11 section 15.8
A dispatch design typically specifies:
- A dispatch function, such as (fn [form] (:op form)), that extracts the value used for method selection. section 15.11
- Implementations registered with defmethod for dispatch values, hierarchy categories, or a :default fallback. section 15.11
- Resolution rules for overlapping matches; prefer-method resolves ambiguity when multiple methods apply. section 15.11
- Runtime inspection and maintenance through methods, remove-method, and related multimethod operations. section 15.11
Dispatching an expression evaluator
(defmulti calculate (fn [form] (:op form))) (defmethod calculate 'plus [{:keys [expr]}] (apply + (map calculate expr))) (defmethod calculate nil [[_ number]] number) (calculate {:op 'plus :expr [[:n 2] [:n 3]]}) ;; 5 A custom hierarchy can group operations by arity, while a :default method can throw for unknown expressions. section 15.11
(defn- add-ops [hierarchy ops] ; #1
(reduce
(fn [h [op [f kind]]] (derive h op kind))
hierarchy
ops))
(def hierarchy ; #2
(add-ops (make-hierarchy) ops))
(defn resolve-op [ops op] ; #3
(first (ops op)))
(do ; #4
(def calculate nil)
(defmulti calculate
(fn [form] (:op form))
:hierarchy #'hierarchy))
(defmethod calculate :varargs ; #5
[{:keys [op expr]}]
(apply (resolve-op ops op) (map calculate expr)))
(defmethod calculate :onearg
[{op :op [x] :expr}]
((resolve-op ops op) (calculate x)))
(defmethod calculate :twoargs
[{op :op [x y] :expr}]
((resolve-op ops op) (calculate x) (calculate y)))
(defmethod calculate nil
[[_ number]] ; #6
number)
(defmethod calculate :default
[form]
(throw
(RuntimeException.
(str "Don't know how to calculate " form))))
(calculate total-payments) ; #7
;; 205659.10262863498
Browse the complete hierarchy-based evaluator, including varargs, one-argument, two-argument, default, and numeric leaf methods. section 15.11

