Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

29
Bending Clojure to your Will: Macros and Domain Specific Languages CUFP - Boston, 2013 Leonardo Borges @leonardo_borges www.leonardoborges.com www.thoughtworks.com Thursday, 19 September 13

description

Slides used for the exercises in the Macros hands-on at LambdaJam 2013 in Brisbane, Australia and CUFP 2013 in Boston, USA.

Transcript of Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

Page 1: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

Bending Clojure to your Will: Macros and Domain Specific

LanguagesCUFP - Boston, 2013

Leonardo Borges@leonardo_borgeswww.leonardoborges.comwww.thoughtworks.com

Thursday, 19 September 13

Page 2: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

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

Page 3: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

Why macros?

Thursday, 19 September 13

Page 4: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

It’s fun

Thursday, 19 September 13

Page 5: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

Thursday, 19 September 13

Page 6: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

It’s powerful

Thursday, 19 September 13

Page 7: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

Thursday, 19 September 13

Page 8: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

It’s mind bending

Thursday, 19 September 13

Page 9: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

Thursday, 19 September 13

Page 10: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

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

Page 11: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

But what are macros?

Thursday, 19 September 13

Page 12: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

•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

Page 13: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

Macro-expansion time

(defmacro arg-logger [& args] (prn "Called with: " args) `(do ~@args))

Thursday, 19 September 13

Page 14: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

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

Page 15: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

Runtime

(arg-logger (+ 2 3))

;;"Called with: " ((+ 2 3))

Arguments are handed into macros unevaluated

Thursday, 19 September 13

Page 16: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

More on that later

Thursday, 19 September 13

Page 17: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

Debugging macros

(macroexpand '(cond true "true" :else "false"))

;;(if true "true" (clojure.core/cond :else "false"))

Thursday, 19 September 13

Page 18: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

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

Page 19: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

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

Page 20: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

Syntax-quote

Automatically qualifies all unqualified symbols

`my-list ; user/my-list`prn ; clojure.core/prn

Note the backtick!

Thursday, 19 September 13

Page 21: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

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

Page 22: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

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

Page 23: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

Unquote-splicing

After...

`(+ ~@my-list) ;;(clojure.core/+ 1 2 3)

(eval `(+ ~@my-list)) ;;6

Thursday, 19 September 13

Page 24: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

All of these are useful inside macros!

Thursday, 19 September 13

Page 25: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

Jam time!

Thursday, 19 September 13

Page 26: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

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

Page 27: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

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

Page 28: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

Questions?Leonardo Borges

@leonardo_borgeswww.leonardoborges.comwww.thoughtworks.com

Thursday, 19 September 13

Page 29: Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013

Go deeper

Let Over Lambda - http://bit.ly/let-over-lambda

On Lisp - http://bit.ly/on-lisp-book

Thursday, 19 September 13