View
760
Download
0
Category
Preview:
DESCRIPTION
Slides used for the exercises in the Macros hands-on at LambdaJam 2013 in Brisbane, Australia and CUFP 2013 in Boston, USA.
Citation preview
Bending Clojure to your Will: Macros and Domain Specific
LanguagesCUFP - Boston, 2013
Leonardo Borges@leonardo_borgeswww.leonardoborges.comwww.thoughtworks.com
Thursday, 19 September 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, 19 September 13
Why macros?
Thursday, 19 September 13
It’s fun
Thursday, 19 September 13
Thursday, 19 September 13
It’s powerful
Thursday, 19 September 13
Thursday, 19 September 13
It’s mind bending
Thursday, 19 September 13
Thursday, 19 September 13
If you give someone Fortran, he has Fortran.If you give someone Lisp, he has any language he pleases.
- Guy Steele
Thursday, 19 September 13
But what are macros?
Thursday, 19 September 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, 19 September 13
Macro-expansion time
(defmacro arg-logger [& args] (prn "Called with: " args) `(do ~@args))
Thursday, 19 September 13
Macro-expansion time
(arg-logger (+ 2 3))
Every usage of a macro
(do (+ 2 3))
Gets replaced with its expansion
prior to compilationThursday, 19 September 13
Runtime
(arg-logger (+ 2 3))
;;"Called with: " ((+ 2 3))
Arguments are handed into macros unevaluated
Thursday, 19 September 13
More on that later
Thursday, 19 September 13
Debugging macros
(macroexpand '(cond true "true" :else "false"))
;;(if true "true" (clojure.core/cond :else "false"))
Thursday, 19 September 13
Debugging macros(require '[clojure.walk :as w])
(w/macroexpand-all '(cond true "true" :else "false"))
;;(if true "true" (if :else "false" nil))
Thursday, 19 September 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, 19 September 13
Syntax-quote
Automatically qualifies all unqualified symbols
`my-list ; user/my-list`prn ; clojure.core/prn
Note the backtick!
Thursday, 19 September 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, 19 September 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, 19 September 13
Unquote-splicing
After...
`(+ ~@my-list) ;;(clojure.core/+ 1 2 3)
(eval `(+ ~@my-list)) ;;6
Thursday, 19 September 13
All of these are useful inside macros!
Thursday, 19 September 13
Jam time!
Thursday, 19 September 13
Jam time!
•Get the code - http://bit.ly/cufp-2013-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, 19 September 13
Summary(defmacro macro-name [& args] ...)Defining macros
(def my-list '(1 2 3))Quoting
`(+ my-list) ; (clojure.core/+ user/my-list)Syntax-quote
`(+ ~my-list) ; (clojure.core/+ (1 2 3))Unquote
(macroexpand '...)
(require '[clojure.walk :as w])(w/macroexpand-all '...)
Debugging
Unquote-splicing `(+ ~@my-list) ; (clojure.core/+ 1 2 3)
Thursday, 19 September 13
Questions?Leonardo Borges
@leonardo_borgeswww.leonardoborges.comwww.thoughtworks.com
Thursday, 19 September 13
Go deeper
Let Over Lambda - http://bit.ly/let-over-lambda
On Lisp - http://bit.ly/on-lisp-book
Thursday, 19 September 13
Recommended