Presentation is loading. Please wait.

Presentation is loading. Please wait.

Feb 17, 2015 Clojure 4. Macros Code is data We have heard this before. It is what makes Lisp so amenable to the use of macros. Examples from Mastering.

Similar presentations


Presentation on theme: "Feb 17, 2015 Clojure 4. Macros Code is data We have heard this before. It is what makes Lisp so amenable to the use of macros. Examples from Mastering."— Presentation transcript:

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.


Download ppt "Feb 17, 2015 Clojure 4. Macros Code is data We have heard this before. It is what makes Lisp so amenable to the use of macros. Examples from Mastering."

Similar presentations


Ads by Google