tirsdag 20. desember 2011 Julekalender Clojure Pattern matching
I tilfelle du ikke synes det er nok med én blogpost hver dag har jeg her en knøttliten bonus til deg. Jeg har jo nå vist deg Euler 1 løst på forskjellige måter i et utall språk. Blant annet har jeg vist hvordan oppgaven kan løses ved hjelp av pattern matching – dette gjorde jeg i F# og i Nemerle, og Kråkelefse delte også en lignende løsning i Haskell.
Når jeg da nylig kom over et matching-biblotek for Clojure måtte jeg nesten teste denne muligheten ut også i det språket. Måtte leke meg litt. Man kan trygt si at multiplene av 3 og 5 har gjort meg litt ensporet. Anyways, here goes...
10 (ns euler1CljMatch.core 11 (:use [clojure.core.match :only [match]])) 12 13 (let [mod-zero? #(zero? (mod %2 %1))] 14 (def mod-zero-3? (partial mod-zero? 3)) 15 (def mod-zero-5? (partial mod-zero? 5))) 16 17 (defn mult3or5? [x] 18 (match [x] 19 [(_ :when mod-zero-3?)] true 20 [(_ :when mod-zero-5?)] true 21 :else false)) 22 23 (defn euler-1 [] 24 (loop [n 0, sum 0] 25 (match [n] 26 [ 1000 ] sum 27 [(_ :when mult3or5?)] (recur (inc n) (+ sum n)) 28 [ _ ] (recur (inc n) sum)))) 29 30 (println (euler-1))
Det er langt fra optimalt å bruke match til dette her, og det illustrerer heller ikke hva pattern matching er godt for. Men jeg måtte bare få det ut! Viktig å test nye muligheter.
For ordens skyld: I slike situasjoner (som det jeg har rotet meg opp i ved å forsøke å bruke match) foretrekker Lisp'ere å bruke en makro som heter cond. I dette tilfellet gir det mye renere syntaks:
17 (defn mult3or5? [x] 18 (cond (mod-zero-3? x) true 19 (mod-zero-5? x) true 20 :else false)) 21 22 (defn euler-1 [] 23 (loop [n 0, sum 0] 24 (cond (= n 1000) sum 25 (mult3or5? n) (recur (inc n) (+ sum n)) 26 :else (recur (inc n) sum))))
Og så var det fire dager igjen til Jul :D