I seem to have a hard time understanding how the below code works. And more precisely how the defined function handles passed parameters
(defmulti encounter
(fn [x y] [(:role x) (:role y)]))
(defmethod encounter [:manager :boss] [x y]
:promise-unrealistic-deadlines)
(defmethod encounter [:manager :developer] [x y]
:demand-overtime)
....
Why do we have 2 vectors ([x y] [(:role x) (:role y)]
) when defining the "encounter". Does this mean that the function takes to vector parameter? If so why do I have to call the function like:
(encounter {:role :manager} {:role :boss})
Isn't the above call passing the first hashmap to [x y] and the second to [(:role x) (:role y)]). I just can't understand how does x get the value :manager and y gets the value of :boss.
The above example is from here: https://yogthos.github.io/ClojureDistilled.html
The second argument passed to the defmulti
macro is called a dispatch function. Here, it accepts two arguments, x
and y
, each of which is expected to be a map with a :role
key in it. The value returned by the dispatch function is called a dispatch value. It is being compared against whenever you call encounter
.
Every definition of the encounter
method takes some dispatch value as its second argument. In your example, that value is produced by passing the arguments x
and y
into the dispatch function (fn [x y] [(:role x) (:role y)])
inside defmulti
. Depending on the value returned by that function, either a corresponding method is invoked, or an IllegalArgumentException
is thrown:
(encounter {:role :designer} {:role :developer})
produces
IllegalArgumentException No method in multimethod 'encounter' for dispatch value: [:designer :developer] clojure.lang.MultiFn.getFn (MultiFn.java:156)
But adding a new possible dispatch value fixes it:
(defmethod encounter [:designer :developer] [x y]
:discuss-video-games)
(encounter {:role :designer} {:role :developer})
=> :discuss-video-games
There's also a dedicated clojuredocs page with more good examples.