Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... ·...

29
Bending Clojure to your Will: Macros and Domain Specific Languages LambdaJam - Brisbane, 2013 Leonardo Borges @leonardo_borges www.leonardoborges.com www.thoughtworks.com Thursday, 16 May 13

Transcript of Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... ·...

Page 1: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

Bending Clojure to your Will: Macros and Domain Specific

LanguagesLambdaJam - Brisbane, 2013

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

Thursday, 16 May 13

Page 2: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

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

Page 3: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

Why macros?

Thursday, 16 May 13

Page 4: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

It’s fun

Thursday, 16 May 13

Page 5: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

Thursday, 16 May 13

Page 6: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

It’s powerful

Thursday, 16 May 13

Page 7: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

Thursday, 16 May 13

Page 8: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

It’s mind bending

Thursday, 16 May 13

Page 9: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

Thursday, 16 May 13

Page 10: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

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

Page 11: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

But what are macros?

Thursday, 16 May 13

Page 12: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

•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

Page 13: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

Macro-expansion time

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

Thursday, 16 May 13

Page 14: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

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

Page 15: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

Runtime

(arg-logger (+ 2 3))

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

Arguments are handed into macros unevaluated

Thursday, 16 May 13

Page 16: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

More on that later

Thursday, 16 May 13

Page 17: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

Debugging macros

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

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

Thursday, 16 May 13

Page 18: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

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

Page 19: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

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

Page 20: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

Syntax-quote

Automatically qualifies all unqualified symbols

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

Note the backtick!

Thursday, 16 May 13

Page 21: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

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

Page 22: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

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

Page 23: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

Unquote-splicing

After...

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

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

Thursday, 16 May 13

Page 24: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

All of these are useful inside macros!

Thursday, 16 May 13

Page 25: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

Jam time!

Thursday, 16 May 13

Page 26: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

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

Page 27: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

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

Page 28: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

Questions?Leonardo Borges

@leonardo_borgeswww.leonardoborges.comwww.thoughtworks.com

Thursday, 16 May 13

Page 29: Bending Clojure to your Will: Macros and Domain Specific ... › yowlambdajam2013 › ... · Leonardo Borges @leonardo_borges • Thoughtworker • Functional Programming enthusiast

Go deeper

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

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

Thursday, 16 May 13