SlideShare una empresa de Scribd logo
1 de 80
Descargar para leer sin conexión
Continuation-passing style and
     Macros with Clojure




                          Leonardo Borges
                          @leonardo_borges
                          http://www.leonardoborges.com
                          http://www.thoughtworks.com
CPS in a nutshell
• not new. It was coined in 1975 by Gerald Sussman and Guy Steele
• style of programming where control is passed explicitly in the form of a
continuation
• every function receives an extra argument k - the continuation
• makes implicit things explicit, such as order of evaluation, procedure
returns, intermediate values...
• used by functional language compilers as an intermediate representation
(e.g.: Scheme, ML, Haskell)
CPS - Pythagorean theorem
 You know the drill...
 a² + b² = c²

 ;;direct style
 (defn pyth [a b]
   (+ (* a a) (* b b)))
CPS - Pythagorean theorem
 You know the drill...
 a² + b² = c²

 ;;direct style
 (defn pyth [a b]
   (+ (* a a) (* b b)))


 ;;CPS
 (defn pyth-cps [a b k]
   (*-cps a a (fn [a2]
                (*-cps b b (fn [b2]
                             (+-cps a2 b2 k))))))
WTF?!
Untangling pyth-cps
;;CPS
(defn *-cps [x y k]
  (k (* x y)))

(defn +-cps [x y k]
  (k (+ x y)))

(defn pyth-cps [a b k]
  (*-cps a a (fn [a2]
               (*-cps b b (fn [b2]
                            (+-cps a2 b2 k))))))
Untangling pyth-cps
;;CPS
(defn *-cps [x y k]
  (k (* x y)))

(defn +-cps [x y k]
  (k (+ x y)))

(defn pyth-cps [a b k]
  (*-cps a a (fn [a2]
               (*-cps b b (fn [b2]
                            (+-cps a2 b2 k))))))

(pyth-cps 5 6 identity) ;61
CPS - Fibonacci
;;direct style
(defn fib [n]
  (if (<= n 1)
    n
    (+ (fib (- n 1)) (fib (- n 2)))))
CPS - Fibonacci
;;CPS
(defn fib-cps [n k]
  (letfn [(cont [n1]
            (fib-cps (- n 2) (fn [n2]
                               (k (+ n1 n2)))))]
    (if (<= n 1)
      (k n)
      (recur (- n 1) cont))))

(fib-cps 20 identity);55
Another look at CPS

Think of it in terms of up to three functions:

• accept: decides when the computation should end
• return continuation: wraps the return value
• next continuation: provides the next step of the computation
CPS - Fibonacci
;;CPS
(defn fib-cps [n k]
  (letfn [(cont [n1]
            (fib-cps (- n 2) (fn [n2]
                               (k (+ n1 n2)))))]
    (if (<= n 1)
      (k n)
      (recur (- n 1) cont))))         accept function

(fib-cps 20 identity);55
CPS - Fibonacci
;;CPS
(defn fib-cps [n k]
  (letfn [(cont [n1]
            (fib-cps (- n 2) (fn [n2]
                               (k (+ n1 n2)))))]
    (if (<= n 1)
      (k n)                     return continuation
      (recur (- n 1) cont))))

(fib-cps 20 identity);55
CPS - Fibonacci
;;CPS
(defn fib-cps [n k]               next continuation
  (letfn [(cont [n1]
            (fib-cps (- n 2) (fn [n2]
                               (k (+ n1 n2)))))]
    (if (<= n 1)
      (k n)
      (recur (- n 1) cont))))

(fib-cps 20 identity);55
CPS - generic function
        builders
(defn mk-cps [accept? end-value kend kont]
  (fn [n]
    ((fn [n k]
       (let [cont (fn [v] (k (kont v n)))]
          (if (accept? n)
            (k end-value)
            (recur (dec n) cont))))
      n kend)))
CPS - generic function
        builders
;;Factorial
(def fac (mk-cps zero? 1 identity #(* %1 %2)))
(fac 10); 3628800

;;Triangular number
(def tri (mk-cps zero? 1 dec #(+ %1 %2)))
(tri 10); 55
Seaside - a more practical use
            of CPS

  • continuation-based web application framework for Smalltalk
  • UI is built as a tree of independent, stateful components
  • uses continuations to model multiple independent flows between
  different components
Seaside - a more practical use
            of CPS

  • continuation-based web application framework for Smalltalk
  • UI is built as a tree of independent, stateful components
  • uses continuations to model multiple independent flows between
  different components


  • memory intensive
  • not RESTful by default
Seaside - Task example [1]

    go
    " [ self chooseCheese.
    "   self confirmCheese ] whileFalse.
    " self informCheese




                                           [1] Try it yourself (http://bit.ly/seaside-task)
Seaside - Task example

chooseCheese
" cheese := self
" " chooseFrom: #( 'Greyerzer' 'Tilsiter' 'Sbrinz' )
" " caption: 'What''s your favorite Cheese?'.
" cheese isNil ifTrue: [ self chooseCheese ]

confirmCheese
" ^ self confirm: 'Is ' , cheese ,   'your favorite Cheese?'

informCheese
" self inform: 'Your favorite is ' , cheese , '.'
CPS - Other real world
       usages
• web interactions ~ continuation invocation [2]
• event machine + fibers in the Ruby world [3]
• functional language compilers
• ajax requests in javascript - callbacks anyone?
• node.js - traditionally blocking functions take a callback instead
• ...




                                                        [2] Automatically RESTful Web Applications (http://bit.ly/ydltH6)
                                                        [3] Untangling Evented Code with Ruby Fibers (http://bit.ly/xm0t51)
Macros

If you give someone Fortran, he has Fortran.
If you give someone Lisp, he has any language he pleases.
                                                            - Guy Steele
Macros

•   Data is code is data
•   Programs that write programs
•   Magic happens at compile time
•   Most control structures in Clojure are built out of macros
e.g.: avoiding nesting levels
 (def guitar
   {:model "EC-401FM"
     :brand "ESP"
     :specs {
              :pickups {:neck {:brand "EMG"
                                :model "EMG 60"}
                        :bridge {:brand "EMG"
                                  :model "EMG 81"}}
              :body "Mahoganny"
              :neck "Mahoganny"}})
e.g.: avoiding nesting levels
 (def guitar
   {:model "EC-401FM"
     :brand "ESP"
     :specs {
              :pickups {:neck {:brand "EMG"
                                :model "EMG 60"}
                        :bridge {:brand "EMG"
                                  :model "EMG 81"}}
              :body "Mahoganny"
              :neck "Mahoganny"}})



     (:model (:neck (:pickups (:specs guitar))))
e.g.: avoiding nesting levels

 what if we could achieve the same like this instead?

 (t guitar :specs :pickups :neck :model)
Macros to the rescue!
(defmacro t
  ([v form] (if (seq? form)
              `(~(first form) ~v ~@(rest form))
              (list form v)))
  ([v form & rest] `(t (t ~v ~form) ~@rest)))
Macros to the rescue!
(defmacro t
  ([v form] (if (seq? form)
              `(~(first form) ~v ~@(rest form))
              (list form v)))
  ([v form & rest] `(t (t ~v ~form) ~@rest)))




       (t guitar :specs :pickups :neck :model)
What’s with all that `~@ ?
Quoting
Prevents evaluation
Quoting
Prevents evaluation

(def my-list (1 2 3))
Quoting
Prevents evaluation

(def my-list (1 2 3))
;java.lang.Integer cannot be cast to clojure.lang.IFn
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!
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
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)
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)


Syntax-quote: automatically qualifies all unqualified symbols
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)


Syntax-quote: automatically qualifies all unqualified symbols

`my-list ;user/my-list
Unquote

Evaluates some forms in a quoted expression
Unquote

Evaluates some forms in a quoted expression

Before unquoting...
Unquote

Evaluates some forms in a quoted expression

Before unquoting...
`(map even? my-list)
Unquote

Evaluates some forms in a quoted expression

Before unquoting...
`(map even? my-list)
;;(clojure.core/map clojure.core/even? user/my-list)
Unquote

Evaluates some forms in a quoted expression

Before unquoting...
`(map even? my-list)
;;(clojure.core/map clojure.core/even? user/my-list)

After...
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)
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)))
Unquote-splicing
Unpacks the sequence at hand
Unquote-splicing
Unpacks the sequence at hand

Before unquote-splicing...
Unquote-splicing
Unpacks the sequence at hand

Before unquote-splicing...
`(+ ~my-list)
Unquote-splicing
Unpacks the sequence at hand

Before unquote-splicing...
`(+ ~my-list)
;;(clojure.core/+ (1 2 3))
Unquote-splicing
Unpacks the sequence at hand

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


(eval `(+ ~my-list))
Unquote-splicing
Unpacks the sequence at hand

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


(eval `(+ ~my-list))
;;java.lang.Integer cannot be cast to clojure.lang.IFn
Unquote-splicing
Unpacks the sequence at hand

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


(eval `(+ ~my-list))
;;java.lang.Integer cannot be cast to clojure.lang.IFn


After...
Unquote-splicing
Unpacks the sequence at hand

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


(eval `(+ ~my-list))
;;java.lang.Integer cannot be cast to clojure.lang.IFn


After...
`(+ ~@my-list)
Unquote-splicing
Unpacks the sequence at hand

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


(eval `(+ ~my-list))
;;java.lang.Integer cannot be cast to clojure.lang.IFn


After...
`(+ ~@my-list)
;;(clojure.core/+ 1 2 3)
Unquote-splicing
Unpacks the sequence at hand

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


(eval `(+ ~my-list))
;;java.lang.Integer cannot be cast to clojure.lang.IFn


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

(eval `(+ ~@my-list)) ;6
back to our macro...
(defmacro t
  ([v form] (if (seq? form)
              `(~(first form) ~v ~@(rest form))
              (list form v)))
  ([v form & rest] `(t (t ~v ~form) ~@rest)))
back to our macro...
(defmacro t
  ([v form] (if (seq? form)
              `(~(first form) ~v ~@(rest form))
              (list form v)))
  ([v form & rest] `(t (t ~v ~form) ~@rest)))




                      better now?
Macro expansion
Macro expansion
(macroexpand '(t guitar :specs :pickups :neck :model))
Macro expansion
(macroexpand '(t guitar :specs :pickups :neck :model))

;;expands to
Macro expansion
(macroexpand '(t guitar :specs :pickups :neck :model))

;;expands to
(:model (user/t (user/t (user/t guitar :specs) :pickups) :neck))
Macro expansion
(macroexpand '(t guitar :specs :pickups :neck :model))

;;expands to
(:model (user/t (user/t (user/t guitar :specs) :pickups) :neck))

(require '[clojure.walk :as walk])
Macro expansion
(macroexpand '(t guitar :specs :pickups :neck :model))

;;expands to
(:model (user/t (user/t (user/t guitar :specs) :pickups) :neck))

(require '[clojure.walk :as walk])
(walk/macroexpand-all '(t guitar :specs :pickups :neck :model))
Macro expansion
(macroexpand '(t guitar :specs :pickups :neck :model))

;;expands to
(:model (user/t (user/t (user/t guitar :specs) :pickups) :neck))

(require '[clojure.walk :as walk])
(walk/macroexpand-all '(t guitar :specs :pickups :neck :model))

;;expands to
Macro expansion
(macroexpand '(t guitar :specs :pickups :neck :model))

;;expands to
(:model (user/t (user/t (user/t guitar :specs) :pickups) :neck))

(require '[clojure.walk :as walk])
(walk/macroexpand-all '(t guitar :specs :pickups :neck :model))

;;expands to
(:model (:neck (:pickups (:specs guitar))))
Macro expansion
(macroexpand '(t guitar :specs :pickups :neck :model))

;;expands to
(:model (user/t (user/t (user/t guitar :specs) :pickups) :neck))

(require '[clojure.walk :as walk])
(walk/macroexpand-all '(t guitar :specs :pickups :neck :model))

;;expands to
(:model (:neck (:pickups (:specs guitar))))


          However our macro is worthless. Clojure implements this
          for us, in the form of the -> [4] macro



                                                        [4] The -> macro on ClojureDocs (http://bit.ly/yCyrHL)
Implementing unless

    We want...

    (unless (zero? 2)
      (print "Not zero!"))
1st try - function
1st try - function
 (defn unless [predicate body]
   (when (not predicate)
     body))
1st try - function
 (defn unless [predicate body]
   (when (not predicate)
     body))

 (unless (zero? 2)
   (print "Not zero!"))
 ;;Not zero!
1st try - function
 (defn unless [predicate body]
   (when (not predicate)
     body))

 (unless (zero? 2)
   (print "Not zero!"))
 ;;Not zero!

 (unless (zero? 0)
   (print "Not zero!"))
 ;;Not zero!
1st try - function
 (defn unless [predicate body]
   (when (not predicate)
     body))

 (unless (zero? 2)
   (print "Not zero!"))
 ;;Not zero!

 (unless (zero? 0)
   (print "Not zero!"))
 ;;Not zero!

            Oh noes!
1st try - function

 Function arguments are eagerly evaluated!
Unless - our second macro
    (defmacro unless [predicate body]
      `(when (not ~predicate)
         ~@body))
Unless - our second macro
    (defmacro unless [predicate body]
      `(when (not ~predicate)
         ~@body))

    (macroexpand '(unless (zero? 2)
Unless - our second macro
    (defmacro unless [predicate body]
      `(when (not ~predicate)
         ~@body))

    (macroexpand '(unless (zero? 2)
                    (print "Not zero!")))
Unless - our second macro
    (defmacro unless [predicate body]
      `(when (not ~predicate)
         ~@body))

    (macroexpand '(unless (zero? 2)
                    (print "Not zero!")))


    ;;expands to
Unless - our second macro
    (defmacro unless [predicate body]
      `(when (not ~predicate)
         ~@body))

    (macroexpand '(unless (zero? 2)
                    (print "Not zero!")))


    ;;expands to
    (if (clojure.core/not (zero? 2))
Unless - our second macro
    (defmacro unless [predicate body]
      `(when (not ~predicate)
         ~@body))

    (macroexpand '(unless (zero? 2)
                    (print "Not zero!")))


    ;;expands to
    (if (clojure.core/not (zero? 2))
      (do (print "Not zero!")))
Unless - our second macro
    (defmacro unless [predicate body]
      `(when (not ~predicate)
         ~@body))

    (macroexpand '(unless (zero? 2)
                    (print "Not zero!")))


    ;;expands to
    (if (clojure.core/not (zero? 2))
      (do (print "Not zero!")))

     You could of course use the if-not [5] macro to the
     same effect
                                              [5] The if-not macro on ClojureDocs (http://bit.ly/yOIk3W)
Thanks!

Questions?!
         Leonardo Borges
        @leonardo_borges
 http://www.leonardoborges.com
  http://www.thoughtworks.com
References

• The Joy of Clojure (http://bit.ly/AAj760)
• Automatically RESTful Web Applications (http://bit.ly/ydltH6)
• Seaside (http://www.seaside.st)
• http://en.wikipedia.org/wiki/Continuation-passing_style
• http://matt.might.net/articles/by-example-continuation-passing-style/
• http://en.wikipedia.org/wiki/Static_single_assignment_form




                                                             Leonardo Borges
                                                             @leonardo_borges
                                                             http://www.leonardoborges.com
                                                             http://www.thoughtworks.com

Más contenido relacionado

La actualidad más candente

Monadologie
MonadologieMonadologie
Monadologieleague
 
Scala introduction
Scala introductionScala introduction
Scala introductionvito jeng
 
Scala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldScala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldBTI360
 
Scalaz 8 vs Akka Actors
Scalaz 8 vs Akka ActorsScalaz 8 vs Akka Actors
Scalaz 8 vs Akka ActorsJohn De Goes
 
미려한 UI/UX를 위한 여정
미려한 UI/UX를 위한 여정미려한 UI/UX를 위한 여정
미려한 UI/UX를 위한 여정SeungChul Kang
 
Demystifying functional programming with Scala
Demystifying functional programming with ScalaDemystifying functional programming with Scala
Demystifying functional programming with ScalaDenis
 
The best language in the world
The best language in the worldThe best language in the world
The best language in the worldDavid Muñoz Díaz
 
The Groovy Puzzlers – The Complete 01 and 02 Seasons
The Groovy Puzzlers – The Complete 01 and 02 SeasonsThe Groovy Puzzlers – The Complete 01 and 02 Seasons
The Groovy Puzzlers – The Complete 01 and 02 SeasonsBaruch Sadogursky
 
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵Wanbok Choi
 
Kotlin collections
Kotlin collectionsKotlin collections
Kotlin collectionsMyeongin Woo
 
T3chFest 2016 - The polyglot programmer
T3chFest 2016 - The polyglot programmerT3chFest 2016 - The polyglot programmer
T3chFest 2016 - The polyglot programmerDavid Muñoz Díaz
 
响应式编程及框架
响应式编程及框架响应式编程及框架
响应式编程及框架jeffz
 
Beauty and the beast - Haskell on JVM
Beauty and the beast  - Haskell on JVMBeauty and the beast  - Haskell on JVM
Beauty and the beast - Haskell on JVMJarek Ratajski
 
深入浅出Jscex
深入浅出Jscex深入浅出Jscex
深入浅出Jscexjeffz
 
Jscex: Write Sexy JavaScript (中文)
Jscex: Write Sexy JavaScript (中文)Jscex: Write Sexy JavaScript (中文)
Jscex: Write Sexy JavaScript (中文)jeffz
 

La actualidad más candente (20)

Kotlin, why?
Kotlin, why?Kotlin, why?
Kotlin, why?
 
ECMAScript 6
ECMAScript 6ECMAScript 6
ECMAScript 6
 
Monadologie
MonadologieMonadologie
Monadologie
 
Scala introduction
Scala introductionScala introduction
Scala introduction
 
Scala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldScala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 World
 
EcmaScript 6
EcmaScript 6 EcmaScript 6
EcmaScript 6
 
Scalaz 8 vs Akka Actors
Scalaz 8 vs Akka ActorsScalaz 8 vs Akka Actors
Scalaz 8 vs Akka Actors
 
미려한 UI/UX를 위한 여정
미려한 UI/UX를 위한 여정미려한 UI/UX를 위한 여정
미려한 UI/UX를 위한 여정
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
 
Demystifying functional programming with Scala
Demystifying functional programming with ScalaDemystifying functional programming with Scala
Demystifying functional programming with Scala
 
The best language in the world
The best language in the worldThe best language in the world
The best language in the world
 
The Groovy Puzzlers – The Complete 01 and 02 Seasons
The Groovy Puzzlers – The Complete 01 and 02 SeasonsThe Groovy Puzzlers – The Complete 01 and 02 Seasons
The Groovy Puzzlers – The Complete 01 and 02 Seasons
 
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
[Let'Swift 2019] 실용적인 함수형 프로그래밍 워크샵
 
Kotlin collections
Kotlin collectionsKotlin collections
Kotlin collections
 
T3chFest 2016 - The polyglot programmer
T3chFest 2016 - The polyglot programmerT3chFest 2016 - The polyglot programmer
T3chFest 2016 - The polyglot programmer
 
Eta
EtaEta
Eta
 
响应式编程及框架
响应式编程及框架响应式编程及框架
响应式编程及框架
 
Beauty and the beast - Haskell on JVM
Beauty and the beast  - Haskell on JVMBeauty and the beast  - Haskell on JVM
Beauty and the beast - Haskell on JVM
 
深入浅出Jscex
深入浅出Jscex深入浅出Jscex
深入浅出Jscex
 
Jscex: Write Sexy JavaScript (中文)
Jscex: Write Sexy JavaScript (中文)Jscex: Write Sexy JavaScript (中文)
Jscex: Write Sexy JavaScript (中文)
 

Similar a Continuation Passing Style and Macros in Clojure - Jan 2012

Introduction To Lisp
Introduction To LispIntroduction To Lisp
Introduction To Lispkyleburton
 
ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015Michiel Borkent
 
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
[FT-11][suhorng] “Poor Man's” Undergraduate CompilersFunctional Thursday
 
(map Clojure everyday-tasks)
(map Clojure everyday-tasks)(map Clojure everyday-tasks)
(map Clojure everyday-tasks)Jacek Laskowski
 
Clojure Intro
Clojure IntroClojure Intro
Clojure Introthnetos
 
Clojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVMClojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVMsunng87
 
Functional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsFunctional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsLeonardo Borges
 
JavaScript 2016 for C# Developers
JavaScript 2016 for C# DevelopersJavaScript 2016 for C# Developers
JavaScript 2016 for C# DevelopersRick Beerendonk
 
Lisp Macros in 20 Minutes (Featuring Clojure)
Lisp Macros in 20 Minutes (Featuring Clojure)Lisp Macros in 20 Minutes (Featuring Clojure)
Lisp Macros in 20 Minutes (Featuring Clojure)Phil Calçado
 
Clojure 1.1 And Beyond
Clojure 1.1 And BeyondClojure 1.1 And Beyond
Clojure 1.1 And BeyondMike Fogus
 
RailswayCon 2010 - Dynamic Language VMs
RailswayCon 2010 - Dynamic Language VMsRailswayCon 2010 - Dynamic Language VMs
RailswayCon 2010 - Dynamic Language VMsLourens Naudé
 
Optimizing with persistent data structures (LLVM Cauldron 2016)
Optimizing with persistent data structures (LLVM Cauldron 2016)Optimizing with persistent data structures (LLVM Cauldron 2016)
Optimizing with persistent data structures (LLVM Cauldron 2016)Igalia
 
Compiler Construction | Lecture 13 | Code Generation
Compiler Construction | Lecture 13 | Code GenerationCompiler Construction | Lecture 13 | Code Generation
Compiler Construction | Lecture 13 | Code GenerationEelco Visser
 

Similar a Continuation Passing Style and Macros in Clojure - Jan 2012 (20)

Introduction To Lisp
Introduction To LispIntroduction To Lisp
Introduction To Lisp
 
ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015
 
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
 
(map Clojure everyday-tasks)
(map Clojure everyday-tasks)(map Clojure everyday-tasks)
(map Clojure everyday-tasks)
 
Pune Clojure Course Outline
Pune Clojure Course OutlinePune Clojure Course Outline
Pune Clojure Course Outline
 
Clojure Intro
Clojure IntroClojure Intro
Clojure Intro
 
Clojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVMClojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVM
 
Functional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsFunctional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event Systems
 
Writing Macros
Writing MacrosWriting Macros
Writing Macros
 
JavaScript 2016 for C# Developers
JavaScript 2016 for C# DevelopersJavaScript 2016 for C# Developers
JavaScript 2016 for C# Developers
 
Lisp Macros in 20 Minutes (Featuring Clojure)
Lisp Macros in 20 Minutes (Featuring Clojure)Lisp Macros in 20 Minutes (Featuring Clojure)
Lisp Macros in 20 Minutes (Featuring Clojure)
 
Clojure 1.1 And Beyond
Clojure 1.1 And BeyondClojure 1.1 And Beyond
Clojure 1.1 And Beyond
 
Angular2 for Beginners
Angular2 for BeginnersAngular2 for Beginners
Angular2 for Beginners
 
RailswayCon 2010 - Dynamic Language VMs
RailswayCon 2010 - Dynamic Language VMsRailswayCon 2010 - Dynamic Language VMs
RailswayCon 2010 - Dynamic Language VMs
 
Clojure+ClojureScript Webapps
Clojure+ClojureScript WebappsClojure+ClojureScript Webapps
Clojure+ClojureScript Webapps
 
R and cpp
R and cppR and cpp
R and cpp
 
Full Stack Clojure
Full Stack ClojureFull Stack Clojure
Full Stack Clojure
 
Optimizing with persistent data structures (LLVM Cauldron 2016)
Optimizing with persistent data structures (LLVM Cauldron 2016)Optimizing with persistent data structures (LLVM Cauldron 2016)
Optimizing with persistent data structures (LLVM Cauldron 2016)
 
Faster Python, FOSDEM
Faster Python, FOSDEMFaster Python, FOSDEM
Faster Python, FOSDEM
 
Compiler Construction | Lecture 13 | Code Generation
Compiler Construction | Lecture 13 | Code GenerationCompiler Construction | Lecture 13 | Code Generation
Compiler Construction | Lecture 13 | Code Generation
 

Más de Leonardo Borges

Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015
Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015
Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015Leonardo Borges
 
Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015Leonardo Borges
 
From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019Leonardo Borges
 
The algebra of library design
The algebra of library designThe algebra of library design
The algebra of library designLeonardo Borges
 
High Performance web apps in Om, React and ClojureScript
High Performance web apps in Om, React and ClojureScriptHigh Performance web apps in Om, React and ClojureScript
High Performance web apps in Om, React and ClojureScriptLeonardo Borges
 
Programação functional reativa: lidando com código assíncrono
Programação functional reativa: lidando com código assíncronoProgramação functional reativa: lidando com código assíncrono
Programação functional reativa: lidando com código assíncronoLeonardo Borges
 
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013Leonardo Borges
 
Intro to Clojure's core.async
Intro to Clojure's core.asyncIntro to Clojure's core.async
Intro to Clojure's core.asyncLeonardo Borges
 
Functional Reactive Programming in Clojurescript
Functional Reactive Programming in ClojurescriptFunctional Reactive Programming in Clojurescript
Functional Reactive Programming in ClojurescriptLeonardo Borges
 
Clojure/West 2013 in 30 mins
Clojure/West 2013 in 30 minsClojure/West 2013 in 30 mins
Clojure/West 2013 in 30 minsLeonardo Borges
 
Clojure Reducers / clj-syd Aug 2012
Clojure Reducers / clj-syd Aug 2012Clojure Reducers / clj-syd Aug 2012
Clojure Reducers / clj-syd Aug 2012Leonardo Borges
 
The many facets of code reuse in JavaScript
The many facets of code reuse in JavaScriptThe many facets of code reuse in JavaScript
The many facets of code reuse in JavaScriptLeonardo Borges
 
Heroku addons development - Nov 2011
Heroku addons development - Nov 2011Heroku addons development - Nov 2011
Heroku addons development - Nov 2011Leonardo Borges
 
Clouds against the Floods (RubyConfBR2011)
Clouds against the Floods (RubyConfBR2011) Clouds against the Floods (RubyConfBR2011)
Clouds against the Floods (RubyConfBR2011) Leonardo Borges
 
Clouds Against the Floods
Clouds Against the FloodsClouds Against the Floods
Clouds Against the FloodsLeonardo Borges
 

Más de Leonardo Borges (19)

Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015
Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015
Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015
 
Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015
 
From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019
 
The algebra of library design
The algebra of library designThe algebra of library design
The algebra of library design
 
High Performance web apps in Om, React and ClojureScript
High Performance web apps in Om, React and ClojureScriptHigh Performance web apps in Om, React and ClojureScript
High Performance web apps in Om, React and ClojureScript
 
Programação functional reativa: lidando com código assíncrono
Programação functional reativa: lidando com código assíncronoProgramação functional reativa: lidando com código assíncrono
Programação functional reativa: lidando com código assíncrono
 
Monads in Clojure
Monads in ClojureMonads in Clojure
Monads in Clojure
 
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
 
Intro to Clojure's core.async
Intro to Clojure's core.asyncIntro to Clojure's core.async
Intro to Clojure's core.async
 
Functional Reactive Programming in Clojurescript
Functional Reactive Programming in ClojurescriptFunctional Reactive Programming in Clojurescript
Functional Reactive Programming in Clojurescript
 
Clojure/West 2013 in 30 mins
Clojure/West 2013 in 30 minsClojure/West 2013 in 30 mins
Clojure/West 2013 in 30 mins
 
Clojure Reducers / clj-syd Aug 2012
Clojure Reducers / clj-syd Aug 2012Clojure Reducers / clj-syd Aug 2012
Clojure Reducers / clj-syd Aug 2012
 
The many facets of code reuse in JavaScript
The many facets of code reuse in JavaScriptThe many facets of code reuse in JavaScript
The many facets of code reuse in JavaScript
 
Heroku addons development - Nov 2011
Heroku addons development - Nov 2011Heroku addons development - Nov 2011
Heroku addons development - Nov 2011
 
Clouds against the Floods (RubyConfBR2011)
Clouds against the Floods (RubyConfBR2011) Clouds against the Floods (RubyConfBR2011)
Clouds against the Floods (RubyConfBR2011)
 
Clouds Against the Floods
Clouds Against the FloodsClouds Against the Floods
Clouds Against the Floods
 
Arel in Rails 3
Arel in Rails 3Arel in Rails 3
Arel in Rails 3
 
Testing with Spring
Testing with SpringTesting with Spring
Testing with Spring
 
JRuby in The Enterprise
JRuby in The EnterpriseJRuby in The Enterprise
JRuby in The Enterprise
 

Último

"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 

Último (20)

"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 

Continuation Passing Style and Macros in Clojure - Jan 2012

  • 1. Continuation-passing style and Macros with Clojure Leonardo Borges @leonardo_borges http://www.leonardoborges.com http://www.thoughtworks.com
  • 2. CPS in a nutshell • not new. It was coined in 1975 by Gerald Sussman and Guy Steele • style of programming where control is passed explicitly in the form of a continuation • every function receives an extra argument k - the continuation • makes implicit things explicit, such as order of evaluation, procedure returns, intermediate values... • used by functional language compilers as an intermediate representation (e.g.: Scheme, ML, Haskell)
  • 3. CPS - Pythagorean theorem You know the drill... a² + b² = c² ;;direct style (defn pyth [a b] (+ (* a a) (* b b)))
  • 4. CPS - Pythagorean theorem You know the drill... a² + b² = c² ;;direct style (defn pyth [a b] (+ (* a a) (* b b))) ;;CPS (defn pyth-cps [a b k] (*-cps a a (fn [a2] (*-cps b b (fn [b2] (+-cps a2 b2 k))))))
  • 6. Untangling pyth-cps ;;CPS (defn *-cps [x y k] (k (* x y))) (defn +-cps [x y k] (k (+ x y))) (defn pyth-cps [a b k] (*-cps a a (fn [a2] (*-cps b b (fn [b2] (+-cps a2 b2 k))))))
  • 7. Untangling pyth-cps ;;CPS (defn *-cps [x y k] (k (* x y))) (defn +-cps [x y k] (k (+ x y))) (defn pyth-cps [a b k] (*-cps a a (fn [a2] (*-cps b b (fn [b2] (+-cps a2 b2 k)))))) (pyth-cps 5 6 identity) ;61
  • 8. CPS - Fibonacci ;;direct style (defn fib [n] (if (<= n 1) n (+ (fib (- n 1)) (fib (- n 2)))))
  • 9. CPS - Fibonacci ;;CPS (defn fib-cps [n k] (letfn [(cont [n1] (fib-cps (- n 2) (fn [n2] (k (+ n1 n2)))))] (if (<= n 1) (k n) (recur (- n 1) cont)))) (fib-cps 20 identity);55
  • 10. Another look at CPS Think of it in terms of up to three functions: • accept: decides when the computation should end • return continuation: wraps the return value • next continuation: provides the next step of the computation
  • 11. CPS - Fibonacci ;;CPS (defn fib-cps [n k] (letfn [(cont [n1] (fib-cps (- n 2) (fn [n2] (k (+ n1 n2)))))] (if (<= n 1) (k n) (recur (- n 1) cont)))) accept function (fib-cps 20 identity);55
  • 12. CPS - Fibonacci ;;CPS (defn fib-cps [n k] (letfn [(cont [n1] (fib-cps (- n 2) (fn [n2] (k (+ n1 n2)))))] (if (<= n 1) (k n) return continuation (recur (- n 1) cont)))) (fib-cps 20 identity);55
  • 13. CPS - Fibonacci ;;CPS (defn fib-cps [n k] next continuation (letfn [(cont [n1] (fib-cps (- n 2) (fn [n2] (k (+ n1 n2)))))] (if (<= n 1) (k n) (recur (- n 1) cont)))) (fib-cps 20 identity);55
  • 14. CPS - generic function builders (defn mk-cps [accept? end-value kend kont] (fn [n] ((fn [n k] (let [cont (fn [v] (k (kont v n)))] (if (accept? n) (k end-value) (recur (dec n) cont)))) n kend)))
  • 15. CPS - generic function builders ;;Factorial (def fac (mk-cps zero? 1 identity #(* %1 %2))) (fac 10); 3628800 ;;Triangular number (def tri (mk-cps zero? 1 dec #(+ %1 %2))) (tri 10); 55
  • 16. Seaside - a more practical use of CPS • continuation-based web application framework for Smalltalk • UI is built as a tree of independent, stateful components • uses continuations to model multiple independent flows between different components
  • 17. Seaside - a more practical use of CPS • continuation-based web application framework for Smalltalk • UI is built as a tree of independent, stateful components • uses continuations to model multiple independent flows between different components • memory intensive • not RESTful by default
  • 18. Seaside - Task example [1] go " [ self chooseCheese. " self confirmCheese ] whileFalse. " self informCheese [1] Try it yourself (http://bit.ly/seaside-task)
  • 19. Seaside - Task example chooseCheese " cheese := self " " chooseFrom: #( 'Greyerzer' 'Tilsiter' 'Sbrinz' ) " " caption: 'What''s your favorite Cheese?'. " cheese isNil ifTrue: [ self chooseCheese ] confirmCheese " ^ self confirm: 'Is ' , cheese , 'your favorite Cheese?' informCheese " self inform: 'Your favorite is ' , cheese , '.'
  • 20. CPS - Other real world usages • web interactions ~ continuation invocation [2] • event machine + fibers in the Ruby world [3] • functional language compilers • ajax requests in javascript - callbacks anyone? • node.js - traditionally blocking functions take a callback instead • ... [2] Automatically RESTful Web Applications (http://bit.ly/ydltH6) [3] Untangling Evented Code with Ruby Fibers (http://bit.ly/xm0t51)
  • 21. Macros If you give someone Fortran, he has Fortran. If you give someone Lisp, he has any language he pleases. - Guy Steele
  • 22. Macros • Data is code is data • Programs that write programs • Magic happens at compile time • Most control structures in Clojure are built out of macros
  • 23. e.g.: avoiding nesting levels (def guitar {:model "EC-401FM" :brand "ESP" :specs { :pickups {:neck {:brand "EMG" :model "EMG 60"} :bridge {:brand "EMG" :model "EMG 81"}} :body "Mahoganny" :neck "Mahoganny"}})
  • 24. e.g.: avoiding nesting levels (def guitar {:model "EC-401FM" :brand "ESP" :specs { :pickups {:neck {:brand "EMG" :model "EMG 60"} :bridge {:brand "EMG" :model "EMG 81"}} :body "Mahoganny" :neck "Mahoganny"}}) (:model (:neck (:pickups (:specs guitar))))
  • 25. e.g.: avoiding nesting levels what if we could achieve the same like this instead? (t guitar :specs :pickups :neck :model)
  • 26. Macros to the rescue! (defmacro t ([v form] (if (seq? form) `(~(first form) ~v ~@(rest form)) (list form v))) ([v form & rest] `(t (t ~v ~form) ~@rest)))
  • 27. Macros to the rescue! (defmacro t ([v form] (if (seq? form) `(~(first form) ~v ~@(rest form)) (list form v))) ([v form & rest] `(t (t ~v ~form) ~@rest))) (t guitar :specs :pickups :neck :model)
  • 28. What’s with all that `~@ ?
  • 31. Quoting Prevents evaluation (def my-list (1 2 3)) ;java.lang.Integer cannot be cast to clojure.lang.IFn
  • 32. 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!
  • 33. 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
  • 34. 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)
  • 35. 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) Syntax-quote: automatically qualifies all unqualified symbols
  • 36. 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) Syntax-quote: automatically qualifies all unqualified symbols `my-list ;user/my-list
  • 37. Unquote Evaluates some forms in a quoted expression
  • 38. Unquote Evaluates some forms in a quoted expression Before unquoting...
  • 39. Unquote Evaluates some forms in a quoted expression Before unquoting... `(map even? my-list)
  • 40. Unquote Evaluates some forms in a quoted expression Before unquoting... `(map even? my-list) ;;(clojure.core/map clojure.core/even? user/my-list)
  • 41. Unquote Evaluates some forms in a quoted expression Before unquoting... `(map even? my-list) ;;(clojure.core/map clojure.core/even? user/my-list) After...
  • 42. 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)
  • 43. 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)))
  • 45. Unquote-splicing Unpacks the sequence at hand Before unquote-splicing...
  • 46. Unquote-splicing Unpacks the sequence at hand Before unquote-splicing... `(+ ~my-list)
  • 47. Unquote-splicing Unpacks the sequence at hand Before unquote-splicing... `(+ ~my-list) ;;(clojure.core/+ (1 2 3))
  • 48. Unquote-splicing Unpacks the sequence at hand Before unquote-splicing... `(+ ~my-list) ;;(clojure.core/+ (1 2 3)) (eval `(+ ~my-list))
  • 49. Unquote-splicing Unpacks the sequence at hand Before unquote-splicing... `(+ ~my-list) ;;(clojure.core/+ (1 2 3)) (eval `(+ ~my-list)) ;;java.lang.Integer cannot be cast to clojure.lang.IFn
  • 50. Unquote-splicing Unpacks the sequence at hand Before unquote-splicing... `(+ ~my-list) ;;(clojure.core/+ (1 2 3)) (eval `(+ ~my-list)) ;;java.lang.Integer cannot be cast to clojure.lang.IFn After...
  • 51. Unquote-splicing Unpacks the sequence at hand Before unquote-splicing... `(+ ~my-list) ;;(clojure.core/+ (1 2 3)) (eval `(+ ~my-list)) ;;java.lang.Integer cannot be cast to clojure.lang.IFn After... `(+ ~@my-list)
  • 52. Unquote-splicing Unpacks the sequence at hand Before unquote-splicing... `(+ ~my-list) ;;(clojure.core/+ (1 2 3)) (eval `(+ ~my-list)) ;;java.lang.Integer cannot be cast to clojure.lang.IFn After... `(+ ~@my-list) ;;(clojure.core/+ 1 2 3)
  • 53. Unquote-splicing Unpacks the sequence at hand Before unquote-splicing... `(+ ~my-list) ;;(clojure.core/+ (1 2 3)) (eval `(+ ~my-list)) ;;java.lang.Integer cannot be cast to clojure.lang.IFn After... `(+ ~@my-list) ;;(clojure.core/+ 1 2 3) (eval `(+ ~@my-list)) ;6
  • 54. back to our macro... (defmacro t ([v form] (if (seq? form) `(~(first form) ~v ~@(rest form)) (list form v))) ([v form & rest] `(t (t ~v ~form) ~@rest)))
  • 55. back to our macro... (defmacro t ([v form] (if (seq? form) `(~(first form) ~v ~@(rest form)) (list form v))) ([v form & rest] `(t (t ~v ~form) ~@rest))) better now?
  • 57. Macro expansion (macroexpand '(t guitar :specs :pickups :neck :model))
  • 58. Macro expansion (macroexpand '(t guitar :specs :pickups :neck :model)) ;;expands to
  • 59. Macro expansion (macroexpand '(t guitar :specs :pickups :neck :model)) ;;expands to (:model (user/t (user/t (user/t guitar :specs) :pickups) :neck))
  • 60. Macro expansion (macroexpand '(t guitar :specs :pickups :neck :model)) ;;expands to (:model (user/t (user/t (user/t guitar :specs) :pickups) :neck)) (require '[clojure.walk :as walk])
  • 61. Macro expansion (macroexpand '(t guitar :specs :pickups :neck :model)) ;;expands to (:model (user/t (user/t (user/t guitar :specs) :pickups) :neck)) (require '[clojure.walk :as walk]) (walk/macroexpand-all '(t guitar :specs :pickups :neck :model))
  • 62. Macro expansion (macroexpand '(t guitar :specs :pickups :neck :model)) ;;expands to (:model (user/t (user/t (user/t guitar :specs) :pickups) :neck)) (require '[clojure.walk :as walk]) (walk/macroexpand-all '(t guitar :specs :pickups :neck :model)) ;;expands to
  • 63. Macro expansion (macroexpand '(t guitar :specs :pickups :neck :model)) ;;expands to (:model (user/t (user/t (user/t guitar :specs) :pickups) :neck)) (require '[clojure.walk :as walk]) (walk/macroexpand-all '(t guitar :specs :pickups :neck :model)) ;;expands to (:model (:neck (:pickups (:specs guitar))))
  • 64. Macro expansion (macroexpand '(t guitar :specs :pickups :neck :model)) ;;expands to (:model (user/t (user/t (user/t guitar :specs) :pickups) :neck)) (require '[clojure.walk :as walk]) (walk/macroexpand-all '(t guitar :specs :pickups :neck :model)) ;;expands to (:model (:neck (:pickups (:specs guitar)))) However our macro is worthless. Clojure implements this for us, in the form of the -> [4] macro [4] The -> macro on ClojureDocs (http://bit.ly/yCyrHL)
  • 65. Implementing unless We want... (unless (zero? 2) (print "Not zero!"))
  • 66. 1st try - function
  • 67. 1st try - function (defn unless [predicate body] (when (not predicate) body))
  • 68. 1st try - function (defn unless [predicate body] (when (not predicate) body)) (unless (zero? 2) (print "Not zero!")) ;;Not zero!
  • 69. 1st try - function (defn unless [predicate body] (when (not predicate) body)) (unless (zero? 2) (print "Not zero!")) ;;Not zero! (unless (zero? 0) (print "Not zero!")) ;;Not zero!
  • 70. 1st try - function (defn unless [predicate body] (when (not predicate) body)) (unless (zero? 2) (print "Not zero!")) ;;Not zero! (unless (zero? 0) (print "Not zero!")) ;;Not zero! Oh noes!
  • 71. 1st try - function Function arguments are eagerly evaluated!
  • 72. Unless - our second macro (defmacro unless [predicate body] `(when (not ~predicate) ~@body))
  • 73. Unless - our second macro (defmacro unless [predicate body] `(when (not ~predicate) ~@body)) (macroexpand '(unless (zero? 2)
  • 74. Unless - our second macro (defmacro unless [predicate body] `(when (not ~predicate) ~@body)) (macroexpand '(unless (zero? 2) (print "Not zero!")))
  • 75. Unless - our second macro (defmacro unless [predicate body] `(when (not ~predicate) ~@body)) (macroexpand '(unless (zero? 2) (print "Not zero!"))) ;;expands to
  • 76. Unless - our second macro (defmacro unless [predicate body] `(when (not ~predicate) ~@body)) (macroexpand '(unless (zero? 2) (print "Not zero!"))) ;;expands to (if (clojure.core/not (zero? 2))
  • 77. Unless - our second macro (defmacro unless [predicate body] `(when (not ~predicate) ~@body)) (macroexpand '(unless (zero? 2) (print "Not zero!"))) ;;expands to (if (clojure.core/not (zero? 2)) (do (print "Not zero!")))
  • 78. Unless - our second macro (defmacro unless [predicate body] `(when (not ~predicate) ~@body)) (macroexpand '(unless (zero? 2) (print "Not zero!"))) ;;expands to (if (clojure.core/not (zero? 2)) (do (print "Not zero!"))) You could of course use the if-not [5] macro to the same effect [5] The if-not macro on ClojureDocs (http://bit.ly/yOIk3W)
  • 79. Thanks! Questions?! Leonardo Borges @leonardo_borges http://www.leonardoborges.com http://www.thoughtworks.com
  • 80. References • The Joy of Clojure (http://bit.ly/AAj760) • Automatically RESTful Web Applications (http://bit.ly/ydltH6) • Seaside (http://www.seaside.st) • http://en.wikipedia.org/wiki/Continuation-passing_style • http://matt.might.net/articles/by-example-continuation-passing-style/ • http://en.wikipedia.org/wiki/Static_single_assignment_form Leonardo Borges @leonardo_borges http://www.leonardoborges.com http://www.thoughtworks.com