1 / 16

Feb 17, 2015

Clojure 4. Feb 17, 2015. 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. Transforming code. (read-string “(+ 1 2 3 4 5)”) (class (read-string “(+ 1 2 3 4 5)”))

skow
Télécharger la présentation

Feb 17, 2015

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Clojure 4 Feb 17, 2015

  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 • (defmacrocond “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.

More Related