# Exploring Multi-Methods in Clojure

Currently reading through the Joy of Clojure book I have recently been introduced to Clojure’s multi-method support. I decided that it would be interesting to see this feature in action, so I opened up LightTable and codified some example use-cases.

## FizzBuzz

The implementation below carries on from were my article about FizzBuzz in Clojure left off. Using the two documented `fizz?` and `buzz?` helpers, followed by the `juxt` core function we are able to codify the problem in a highly descriptive manner.

``````(def fizz? #(zero? (mod % 3)))
(def buzz? #(zero? (mod % 5)))

(defmulti fizzbuzz (juxt fizz? buzz?))
(defmethod fizzbuzz [true false] [n] "Fizz")
(defmethod fizzbuzz [false true] [n] "Buzz")
(defmethod fizzbuzz [true true] [n]  "FizzBuzz")
(defmethod fizzbuzz :default [n] (str n))

(->> (range 1 10) (map fizzbuzz)) ; (1 2 "Fizz" 4 "Buzz" "Fizz" 7 8 "Fizz")
``````

## Factorial

We are also able to use multi-methods in a similar manner to pattern-matching found in languages such as Scala and Haskell. The below implementation recursively computes the supplied arguments factorial value, handling the base-case of 0 using the function `identity` as the dispatch call.

``````(defmulti factorial identity)
(defmethod factorial 0 [_] 1)
(defmethod factorial :default [n] (* n (factorial (dec n))))

(factorial 5) ; 120
``````

## Rock-Paper-Scissors

We are able to expand upon the rules based approach laid out in the previous examples by documenting the Rock-Paper-Scissors game in code. Using this multi-method allows us to compute all the possible winning-moves for both players.

``````(defmulti beats? vector)
(defmethod beats? [:paper :rock] [_ _] true)
(defmethod beats? [:scissors :paper] [_ _] true)
(defmethod beats? [:rock :scissors] [_ _] true)
(defmethod beats? :default [_ _] false)

(def winning-moves
(for [one [:rock :paper :scissors]
two [:rock :paper :scissors]
:let [one-wins (beats? one two)
two-wins (beats? two one)]
:when (or one-wins two-wins)]
(if one-wins ["1" one two] ["2" one two])))
; [2 :rock :paper] [1 :rock :scissors] [1 :paper :rock]
; [2 :paper :scissors] [2 :scissors :rock] [1 :scissors :paper])
``````

## Odd or Even

Finally we can use the core `odd?` function to polymorphically return a string depicting the supplied values odd-even status.

``````(defmulti odd-even odd?)
(defmethod odd-even true [n] (str n " is Odd"))
(defmethod odd-even false [n] (str n " is Even"))

(odd-even? 5) ; 5 is Odd
``````