|
; All of this is taken from http://www.braveclojure.com/writing-macros/ |
|
|
|
; you can define a macro that is quote complex |
|
|
|
(defmacro code-critic |
|
"phrases are courtesy Hermes Conrad from Futurama" |
|
[{:keys [good bad]}] |
|
(list 'do |
|
(list 'println |
|
"Great squid of Madrid, this is bad code:" |
|
(list 'quote bad)) |
|
(list 'println |
|
"Sweet gorilla of Manila, this is good code:" |
|
(list 'quote good)))) |
|
|
|
; slight refactor with macro syntax quoting |
|
|
|
(defmacro code-critic |
|
"phrases are courtesy Hermes Conrad from Futurama" |
|
[{:keys [good bad]}] |
|
;; Notice the backtick - that's the syntax quote |
|
`(do (println "Great squid of Madrid, this is bad code:" |
|
(quote ~bad)) |
|
(println "Sweet gorilla of Manila, this is good code:" |
|
(quote ~good)))) |
|
|
|
; usage |
|
; => Cursed bacteria of Liberia, this is bad code: (1 + 1) |
|
; => Sweet sacred boa of Western and Eastern Samoa, this is good code: (+ 1 1) |
|
(code-critic {:good (+ 1 1) :bad (1 + 1)}) |
|
|
|
; and then refactor it so some of the complexity |
|
; is placed inside another function |
|
; that function is then only really useful when |
|
; used from inside the macro |
|
|
|
(defn criticize-code |
|
[criticism code] |
|
`(println ~criticism (quote ~code))) |
|
|
|
(defmacro code-critic |
|
[{:keys [good bad]}] |
|
`(do ~(criticize-code "Cursed bacteria of Liberia, this is bad code:" bad) |
|
~(criticize-code "Sweet sacred boa of Western and Eastern Samoa, this is good code:" good))) |
|
|
|
; more refactoring |
|
(defmacro code-critic |
|
[{:keys [good bad]}] |
|
`(do ~(map #(apply criticize-code %) |
|
[["Great squid of Madrid, this is bad code:" bad] |
|
["Sweet gorilla of Manila, this is good code:" good]]))) |
|
|
|
; uh-oh that caused an error |
|
; use macroexpand to decipher what's happening |
|
; for those short on time, the fix is unquote splicing ~@ |
|
; Unquote splicing is like unwrapping a seq'able data structure (examples below) |
|
|
|
; Without unquote splicing |
|
; => (clojure.core/+ (1 2 3)) |
|
; which would cause an error |
|
`(+ ~(list 1 2 3)) |
|
|
|
; With unquote splicing |
|
; => (clojure.core/+ 1 2 3) |
|
`(+ ~@(list 1 2 3)) |
|
|
|
(defmacro code-critic |
|
[{:keys [good bad]}] |
|
`(do ~@(map #(apply criticize-code %) |
|
[["Sweet lion of Zion, this is bad code:" bad] |
|
["Great cow of Moscow, this is good code:" good]]))) |
|
(code-critic {:good (+ 1 1) :bad (1 + 1)}) |
|
|
|
; final refactoring |
|
|
|
(def criticisms {:good "Sweet manatee of Galilee, this is good code:" |
|
:bad "Sweet giant anteater of Santa Anita, this is bad code:"}) |
|
|
|
(defn criticize-code |
|
[[criticism-key code]] |
|
`(println (~criticism-key criticisms) (quote ~code))) |
|
|
|
(defmacro code-critic |
|
[code-evaluations] |
|
`(do ~@(map criticize-code code-evaluations))) |