Download presentation
Presentation is loading. Please wait.
Published byMarcus Williamson Modified over 8 years ago
1
Feb 17, 2015 Clojure 4
2
Macros Code is data We have heard this before. It is what makes Lisp so amenable to the use of macros. Examples from Mastering Clojure Macros...
3
Transforming code (read-string “(+ 1 2 3 4 5)”) (class (read-string “(+ 1 2 3 4 5)”)) (eval (read-string “(+ 1 2 3 4 5)”)) (class (eval (read-string “(+ 1 2 3 4 5)”))) (let [expression] (read-string “(+ 1 2 3 4 5)”)] (cons (read-string “*”) (rest expression))) (let [expression] (quote (+ 1 2 3 4 5))] (cons (quote *) (rest expression))) ‘(+ 1 2 3 4 5)
4
Our first macro (defmacro when “Evaluates test. If logical true, evaluates body.” [test & body] (list ‘if test (cons ‘do body))) (when (= 2 (+ 1 1)) (print “You got”) (print “ the touch!”) (println))
5
First macro continued (list ‘if ‘(= 2 (+ 1 1)) (cons ‘do ‘((print “You got”) (print “ the touch!”) (println)))) (if (= 2 (+ 1 1)) (do (print “You got”) (print “ the touch!”) (println)))
6
Another example (defmacro cond “Long comment here.” [& clauses] (when clauses (list ‘if (first clauses) (if (next clauses) (second clauses) (throw (IllegalArgumentException. “cond requires an even number of forms”))) (cons ‘clojure.core/cond (next (next clauses))))))
7
macroexpand-1 (macroexpand-1 ‘(when (= 1 2) (println “math is broken”))) (macroexpand-1 nil) (defmacro broken-when [test & body] (list test (cons ‘do body))) Use macroexpand-1 to figure out why this doesn’t work. Note that macroexpand-1 expands one level.
8
macroexpand (defmacro when-falsy [test & body] (list ‘when (list ‘not test) (cons ‘do body))) (macroexpand-1 ‘(when-falsy (= 1 2) (println “hi”))) (macroexpand ‘(when-falsy (= 1 2) (println “hi”)))
9
assert (defmacro assert [x] (when *assert* ;; make sure enabled (list ‘when-not x (list ‘throw (list ‘new AssertionError (list ‘str “Assert failed: “ (list ‘pr-str (list ‘quote x)))))))) (assert (= 1 2)) Real assert is even more complicated.
10
Assert with syntax quote (defmacro assert [x] (when *assert* `(when-not ~x (throw (new AssertionError (str “Assert failed: “ (pr-str ‘~x))))))) Before when-not above is a back-quote (aka a syntax quote). It selectively quotes all but things with ~ or ~@.
11
Syntax quote (def a 4) ‘(1 2 3 a 5) (list 1 2 3 a 5) `(1 2 3 ~a 5) The book says syntax quote (`)is a little cockeyed and ready to party. Unquote (~) is the thing that evaluates inside of syntax quoted code/data. Unquote-splice (~@) is like unquote, but it splices in the result.
12
Unquote-splice (def other-numbers ‘(4 5 6 7 8)) `(1 2 3 ~other-numbers 9 10) (concat ‘(1 2 3) other-numbers ‘( 9 10)) `(1 2 3 ~@other-numbers 9 10)
13
Symbol capture (def y 100) (defmacro make-adder [x] `(fn [~’y] (+ ~x ~’y))) ((make-adder (+ y 3)) 5) Fix the problem with gensym (gensym) generates a unique new symbol
14
Symbol capture cont. (defmacro make-adder [x] (let [y (gensym)] `(fn [~y] (+ ~x ~y)))) Auto-gensym makes this more concise. (defmacro make-adder [x] `(fn [y#] (+ ~x y#)))
15
Another example (defmacro and ([] true) ([x] x) ([x & next] `(let [and# ~x] (if and# (and ~@next) and#))))
16
More detail about and Version that isn’t quite right... (defmacro our-and [x] ([] true) ([x] x) ([x & next] `(if ~x (our-and ~@next) ~x))) (our-and (do (println “hi there”) (= 1 2)) (= 3 4)) Prints “hi there” twice.
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.