Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... ·...
Transcript of Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... ·...
Bending Clojure to your Will: Macros and Domain Specific
LanguagesLambdaJam - Brisbane, 2013
Leonardo Borges@leonardo_borgeswww.leonardoborges.comwww.thoughtworks.com
Thursday, 16 May 13
Leonardo Borges@leonardo_borgeswww.leonardoborges.comwww.thoughtworks.com
• Thoughtworker• Functional Programming enthusiast• Clojure Evangelist• Founder & Organiser of the Sydney Clojure User Group (clj-syd)• World traveller• Fan of Murray’s Beers :)
about:me
Thursday, 16 May 13
Why macros?
Thursday, 16 May 13
It’s fun
Thursday, 16 May 13
Thursday, 16 May 13
It’s powerful
Thursday, 16 May 13
Thursday, 16 May 13
It’s mind bending
Thursday, 16 May 13
Thursday, 16 May 13
If you give someone Fortran, he has Fortran.If you give someone Lisp, he has any language he pleases.
- Guy Steele
Thursday, 16 May 13
But what are macros?
Thursday, 16 May 13
•Data is code is data•Programs that write programs•Magic happens at macro-expansion time•Most control structures in Clojure are built out of macros
But what are macros?
Thursday, 16 May 13
Macro-expansion time
(defmacro arg-logger [& args] (prn "Called with: " args) `(do ~@args))
Thursday, 16 May 13
Macro-expansion time
(arg-logger (+ 2 3))
Every usage of a macro
(do (+ 2 3))
Gets replaced with its expansion
prior to compilationThursday, 16 May 13
Runtime
(arg-logger (+ 2 3))
;;"Called with: " ((+ 2 3))
Arguments are handed into macros unevaluated
Thursday, 16 May 13
More on that later
Thursday, 16 May 13
Debugging macros
(macroexpand '(cond true "true" :else "false"))
;;(if true "true" (clojure.core/cond :else "false"))
Thursday, 16 May 13
Debugging macros(require '[clojure.walk :as w])
(w/macroexpand-all '(cond true "true" :else "false"))
;;(if true "true" (if :else "false" nil))
Thursday, 16 May 13
Quoting Prevents evaluation
(def my-list (1 2 3)) ;java.lang.Integer cannot be cast to clojure.lang.IFn
(def my-list '(1 2 3)) ;Success!
'my-list ;my-list'(1 2 3) ;(1 2 3)
Thursday, 16 May 13
Syntax-quote
Automatically qualifies all unqualified symbols
`my-list ; user/my-list`prn ; clojure.core/prn
Note the backtick!
Thursday, 16 May 13
Unquote
Evaluates some forms in a quoted expression
Before unquoting...`(map even? my-list);;(clojure.core/map clojure.core/even? user/my-list)
After...`(map even? '~my-list);;(clojure.core/map clojure.core/even? (quote (1 2 3)))
Thursday, 16 May 13
Unquote-splicing
“Unpacks” a sequence
Before unquote-splicing...
`(+ ~my-list) ;;(clojure.core/+ (1 2 3))
(eval `(+ ~my-list)) ;;java.lang.Integer cannot be cast to clojure.lang.IFn
Thursday, 16 May 13
Unquote-splicing
After...
`(+ ~@my-list) ;;(clojure.core/+ 1 2 3)
(eval `(+ ~@my-list)) ;;6
Thursday, 16 May 13
All of these are useful inside macros!
Thursday, 16 May 13
Jam time!
Thursday, 16 May 13
Jam time!
•Get the code - http://bit.ly/ylj13-macros•Make sure you have leiningen 2.x installed•Run $lein midje or lein midje :autotest from the project root•Watch the tests fail!•Fix them :)
Thursday, 16 May 13
Summary(defmacro macro-name [& args] ...)Defining macros
(def my-list '(1 2 3))Quoting
`my-list ; user/my-listSyntax-quote
`(+ ~my-list) ;;(clojure.core/+ (1 2 3))Unquote-splicing
(macroexpand '...)
(require '[clojure.walk :as w])(w/macroexpand-all '...)
Debugging
Thursday, 16 May 13
Questions?Leonardo Borges
@leonardo_borgeswww.leonardoborges.comwww.thoughtworks.com
Thursday, 16 May 13
Go deeper
Let Over Lambda - http://bit.ly/let-over-lambda
On Lisp - http://bit.ly/on-lisp-book
Thursday, 16 May 13