bending clojure to your will: macros and domain specific ... › yowlambdajam2013 › ... ·...

Post on 05-Jul-2020

5 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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

top related