SlideShare uma empresa Scribd logo
1 de 30
A little exercise with Macro

          Zehua Liu
Prerequisites
• Basic macro
  (defmacro mywhen [cond-exp & clauses]
    `(if ~cond-exp
       (do
         ~@clauses)))
• Java interop
  (String. "a string")
  (.substring "a string" 0 5)
Motivation
• A script to test a server with a request
  /response protocol
• To send a request to the server, reuse Java
  classes that represent requests in server code
Java Request Classes
Java Request Classes
Sending Login Request
Sending SendMessage Request
Sending Requests
•   Many other types of requests
•   Lots of duplicate codes
•   Refactor them!
•   function?
Refactor using function

(defn send-request [req-pkt sid]
  (let [[new-sid resp-pkts] (send-req req-pkt sid)]
    (if-let [err-msg (check-resp-error resp-pkts)]
      (do
        (println
          (format
            "ERROR: %s failed, sid='%s',req='%s',err='%s'"
            (.getName req-pkt) sid req-pkt err-msg))
        [nil nil])
      [new-sid resp-pkts])))
Refactor using function
Refactor using function
• Not too bad
• Can we do better / differently?
• macro?
Login Request Again
Make it work for Login Request
Make it work for Login Request
(defmacro send-request [request username password sid]
  `(let [req-pkt# (doto (requests.LoginRequest.)
                    (.setUsername ~username)
                    (.setPassword ~password))
        [new-sid# resp-pkts#] (send-req req-pkt# ~sid)]
    (if-let [err-msg# (check-resp-error resp-pkts#)]
      (do
        (println
          (format
            "ERROR: %s failed, sid='%s',req='%s',err='%s'"
            ~(name request) ~sid req-pkt# err-msg#))
        [nil nil])
      [new-sid# resp-pkts#])))

(defn login [:Login username password sid]
  (send-request username password sid))
Make it work for Login Request
Make it work for Login Request
(defmacro send-request [request username password sid]
`(let [req-pkt# (doto (new ~(symbol
                                (str "requests."
                                     (name request)
                                     "Request")))
                    (.setUsername ~username)
                    (.setPassword ~password))
        [new-sid# resp-pkts#] (send-req req-pkt# ~sid)]
    (if-let [err-msg# (check-resp-error resp-pkts#)]
      (do
        (println
          (format
            "ERROR: %s failed, sid='%s',req='%s',err='%s'"
            ~(name request) ~sid req-pkt# err-msg#))
        [nil nil])
      [new-sid# resp-pkts#])))

(defn login [username password sid]
  (send-request :Login username password sid))
Make it work for Login Request
(.setUsername ~username) <==>
  (. setUsername ~username)

(.setUsername ~username) <==>
(. (symbol (str "set" (name :Username))) ~username)

(.setUsername ~username)
(.setPassword ~password) <==>
~@(map (fn [[pn pv]]
           `(. ~(symbol (str "set" (name pn))) ~pv))
   {:Username username :Password password})
Make it work for Login Request
(defmacro send-request [request param-map sid]
  `(let [req-pkt# (doto (new ~(symbol
                                (str "requests." (name request)
                                      "Request")))
                    ~@(map (fn [[pn pv]]
                             `(. ~(symbol (str "set" (name pn))) ~pv))
                          param-map))
        [new-sid# resp-pkts#] (send-req req-pkt# ~sid)]
    (if-let [err-msg# (check-resp-error resp-pkts#)]
      (do
        (println
          (format
            "ERROR: %s failed, sid='%s',req='%s',err='%s'"
            ~(name request) ~sid req-pkt# err-msg#))
        [nil nil])
      [new-sid# resp-pkts#])))

(defn login [username password sid]
  (send-request :Login
                {:Username username :Password password} sid))
Refactor using macro

(defn login [username password sid]
  (send-request :Login
                {:Username username
                 :Password password}
                sid))

(defn send-message [message dest-username type sid]
  (send-request :SendMessage
                {:Message message
                 :DestUsername dest-username
                 :Type type}
                sid))
Refactor using macro
•   It works! Hooray!
•   Let’s use it for more fancy stuff.
•   Optional request fields?
•   On server side, SendMessage type default to
    1, if not specified
Optional field

(defn send-message [message dest-username type sid]
  (send-request :SendMessage
                {:Message message
                 :DestUsername dest-username
                 :Type type}
                sid))

(defn send-message [message dest-username sid]
  (send-request :SendMessage
                {:Message message
                 :DestUsername dest-username}
                sid))
Optional field

(defn send-message
  ([message dest-username sid]
    (send-message message dest-username nil sid))
  ([message dest-username type sid]
    (let [param-map-base {:Message message
                          :DestUsername dest-username}
          param-map (if type
                      (assoc param-map-base :Type type)
                      param-map-base)]
    (send-request :SendMessage param-map sid))))
Optional field, FAILED

(defn send-message
  ([message dest-username sid]
    (send-message message dest-username nil sid))
  ([message dest-username type sid]
    (let [param-map-base {:Message message
                          :DestUsername dest-username}
          param-map (if type
                      (assoc param-map-base :Type type)
                      param-map-base)]
    (send-request :SendMessage param-map sid))))

CompilerException java.lang.IllegalArgumentException: Don't
know how to create ISeq from: clojure.lang.Symbol, compiling:
(NO_SOURCE_PATH:10)
Optional field, FAILED
Optional field, FAILED
• macro is evaluated at compile time, not at run
  time
• macro evaluator only knows about symbols
  – {:Username username :Password
    password} is a map (keywords to symbols)
  – But param-map is a symbol
  – At compile time, macro evaluator does not know
    the run time value that the symbol param-map
    represents
• How do we fix it?
Optional field, Fixing it
• How do we fix it?
• One thought:
  – Tell the macro the complete list of fields, and have
    it generate codes like below for every field:
(if-let [v (:Type param-map)]
  (. setType v))
• And then param-map can be a symbol whose
  value macro evalutor does not need to know,
  its value is only needed at run time.
Optional field, Fixing it
(defmacro send-request [request param-list param-map sid]
  (let [param-map# param-map
        r (gensym)]
  `(let [req-pkt# (let [~r (new ~(symbol
                                 (str "requests." (name request)
                                      "Request")))]
                    ~@(map (fn [pn]
                             `(if-let [pv# (~pn ~param-map#)]
                               (. ~r ~(symbol (str "set" (name pn))) pv#)))
                          param-list))
        [new-sid# resp-pkts#] (send-req req-pkt# ~sid)]
    (if-let [err-msg# (check-resp-error resp-pkts#)]
      (do
        (println
          (format
            "ERROR: %s failed, sid='%s',req='%s',err='%s'"
            ~(name request) ~sid req-pkt# err-msg#))
        [nil nil])
      [new-sid# resp-pkts#]))))
Optional field, Fixing it
(defn login [username password sid]
  (send-request :Login [:Username :Password]
                {:Username username :Password password}
                sid))

(defn send-message
  ([message dest-username sid]
    (send-message message dest-username nil sid))
  ([message dest-username type sid]
    (let [param-map-base {:Message message
                           :DestUsername dest-username}
          param-map (if type
                       (assoc param-map-base :Type type)
                       param-map-base)]
    (send-request :SendMessage
                   [:Message :DestUsername :Type]
                   param-map sid))))
Optional field, Fixing it
(macroexpand '(send-request :SendMessage
                            [:Message :DestUsername :Type] param-map nil))

(let*
  [req-pkt__625__auto__
   (clojure.core/let [G__671 (new requests.SendMessageRequest)]
      (clojure.core/if-let [pv__624__auto__ (:Message param-map)]
        (. G__671 setMessage pv__624__auto__))
      (clojure.core/if-let [pv__624__auto__ (:DestUsername param-map)]
        (. G__671 setDestUsername pv__624__auto__))
      (clojure.core/if-let [pv__624__auto__ (:Type param-map)]
        (. G__671 setType pv__624__auto__)))
   vec__672 (scratch.core/send-req req-pkt__625__auto__ nil)
   new-sid__626__auto__ (clojure.core/nth vec__672 0 nil)
   resp-pkts__627__auto__ (clojure.core/nth vec__672 1 nil)]
  (clojure.core/if-let [err-msg__628__auto__
                (scratch.core/check-resp-error resp-pkts__627__auto__)]
    (do
       (clojure.core/println
         (clojure.core/format
           "ERROR: %s failed, sid='%s',req='%s',err='%s'"
           "SendMessage" nil req-pkt__625__auto__ err-msg__628__auto__))
       [nil nil])
    [new-sid__626__auto__ resp-pkts__627__auto__]))
Lessons Learned
• macro is evaluated at compile time, not at run time
• macro evaluator treats code as data
   – {:Username username :Password password}
     is a map of keywords to symbols, not keywrods to strings
     (or whatever type username/password might be)
   – But param-map is a symbol
• At compile time, macro evaluator treats ref/var as
  symbol, knowing nothing about their run time values

Mais conteúdo relacionado

Mais procurados

Desarrollo de módulos en Drupal e integración con dispositivos móviles
Desarrollo de módulos en Drupal e integración con dispositivos móvilesDesarrollo de módulos en Drupal e integración con dispositivos móviles
Desarrollo de módulos en Drupal e integración con dispositivos móvilesLuis Curo Salvatierra
 
Simple Ways To Be A Better Programmer (OSCON 2007)
Simple Ways To Be A Better Programmer (OSCON 2007)Simple Ways To Be A Better Programmer (OSCON 2007)
Simple Ways To Be A Better Programmer (OSCON 2007)Michael Schwern
 
From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)Night Sailer
 
Beyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeBeyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeAijaz Ansari
 
Programming Lisp Clojure - 2장 : 클로저 둘러보기
Programming Lisp Clojure - 2장 : 클로저 둘러보기Programming Lisp Clojure - 2장 : 클로저 둘러보기
Programming Lisp Clojure - 2장 : 클로저 둘러보기JangHyuk You
 
Ruby - Uma Introdução
Ruby - Uma IntroduçãoRuby - Uma Introdução
Ruby - Uma IntroduçãoÍgor Bonadio
 
MTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new APIMTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new APISix Apart KK
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Kris Wallsmith
 
G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門Tsuyoshi Yamamoto
 
Raleigh Web Design Meetup Group - Sass Presentation
Raleigh Web Design Meetup Group - Sass PresentationRaleigh Web Design Meetup Group - Sass Presentation
Raleigh Web Design Meetup Group - Sass PresentationDaniel Yuschick
 
Windows Server 2008 (PowerShell Scripting Uygulamaları)
Windows Server 2008 (PowerShell Scripting Uygulamaları)Windows Server 2008 (PowerShell Scripting Uygulamaları)
Windows Server 2008 (PowerShell Scripting Uygulamaları)ÇözümPARK
 
F# in the real world (NDC)
F# in the real world (NDC)F# in the real world (NDC)
F# in the real world (NDC)Yan Cui
 
Internationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsInternationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsPierre MARTIN
 
ATK 'Beyond The Pizza Guides'
ATK 'Beyond The Pizza Guides'ATK 'Beyond The Pizza Guides'
ATK 'Beyond The Pizza Guides'Ibuildings
 
Implementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with SlickImplementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with SlickHermann Hueck
 
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014Cliff Seal
 

Mais procurados (20)

Desarrollo de módulos en Drupal e integración con dispositivos móviles
Desarrollo de módulos en Drupal e integración con dispositivos móvilesDesarrollo de módulos en Drupal e integración con dispositivos móviles
Desarrollo de módulos en Drupal e integración con dispositivos móviles
 
Simple Ways To Be A Better Programmer (OSCON 2007)
Simple Ways To Be A Better Programmer (OSCON 2007)Simple Ways To Be A Better Programmer (OSCON 2007)
Simple Ways To Be A Better Programmer (OSCON 2007)
 
From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)
 
Beyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCodeBeyond Breakpoints: Advanced Debugging with XCode
Beyond Breakpoints: Advanced Debugging with XCode
 
Programming Lisp Clojure - 2장 : 클로저 둘러보기
Programming Lisp Clojure - 2장 : 클로저 둘러보기Programming Lisp Clojure - 2장 : 클로저 둘러보기
Programming Lisp Clojure - 2장 : 클로저 둘러보기
 
Ruby - Uma Introdução
Ruby - Uma IntroduçãoRuby - Uma Introdução
Ruby - Uma Introdução
 
MTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new APIMTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new API
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)
 
Python 1
Python 1Python 1
Python 1
 
My First Ruby
My First RubyMy First Ruby
My First Ruby
 
G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門G*ワークショップ in 仙台 Grails(とことん)入門
G*ワークショップ in 仙台 Grails(とことん)入門
 
issue35 zh-CN
issue35 zh-CNissue35 zh-CN
issue35 zh-CN
 
Raleigh Web Design Meetup Group - Sass Presentation
Raleigh Web Design Meetup Group - Sass PresentationRaleigh Web Design Meetup Group - Sass Presentation
Raleigh Web Design Meetup Group - Sass Presentation
 
Windows Server 2008 (PowerShell Scripting Uygulamaları)
Windows Server 2008 (PowerShell Scripting Uygulamaları)Windows Server 2008 (PowerShell Scripting Uygulamaları)
Windows Server 2008 (PowerShell Scripting Uygulamaları)
 
F# in the real world (NDC)
F# in the real world (NDC)F# in the real world (NDC)
F# in the real world (NDC)
 
Internationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsInternationalizing CakePHP Applications
Internationalizing CakePHP Applications
 
ATK 'Beyond The Pizza Guides'
ATK 'Beyond The Pizza Guides'ATK 'Beyond The Pizza Guides'
ATK 'Beyond The Pizza Guides'
 
Ruby 1.9
Ruby 1.9Ruby 1.9
Ruby 1.9
 
Implementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with SlickImplementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with Slick
 
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014
Temporary Cache Assistance (Transients API): WordCamp Birmingham 2014
 

Destaque

Clojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVMClojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVMsunng87
 
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
 
不自然なcar/ナチュラルにconsして
不自然なcar/ナチュラルにconsして不自然なcar/ナチュラルにconsして
不自然なcar/ナチュラルにconsしてmitsutaka mimura
 
Macros in Clojure
Macros in ClojureMacros in Clojure
Macros in Clojuresohta
 
入門ClojureScript
入門ClojureScript入門ClojureScript
入門ClojureScriptsohta
 
Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012Leonardo Borges
 
Stefan Richter - Writing simple, readable and robust code: Examples in Java, ...
Stefan Richter - Writing simple, readable and robust code: Examples in Java, ...Stefan Richter - Writing simple, readable and robust code: Examples in Java, ...
Stefan Richter - Writing simple, readable and robust code: Examples in Java, ...AboutYouGmbH
 
Clojureシンタックスハイライター開発から考えるこれからのlispに必要なもの
Clojureシンタックスハイライター開発から考えるこれからのlispに必要なものClojureシンタックスハイライター開発から考えるこれからのlispに必要なもの
Clojureシンタックスハイライター開発から考えるこれからのlispに必要なものsohta
 
(map Clojure everyday-tasks)
(map Clojure everyday-tasks)(map Clojure everyday-tasks)
(map Clojure everyday-tasks)Jacek Laskowski
 
Introduction to clojure
Introduction to clojureIntroduction to clojure
Introduction to clojureAbbas Raza
 
プログラミング言語Clojureのニャンパスでの活用事例
プログラミング言語Clojureのニャンパスでの活用事例プログラミング言語Clojureのニャンパスでの活用事例
プログラミング言語Clojureのニャンパスでの活用事例sohta
 
Clojure from ground up
Clojure from ground upClojure from ground up
Clojure from ground upDi Xu
 

Destaque (19)

Clojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVMClojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVM
 
A Dive Into Clojure
A Dive Into ClojureA Dive Into Clojure
A Dive Into Clojure
 
Writing Macros
Writing MacrosWriting Macros
Writing Macros
 
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
 
不自然なcar/ナチュラルにconsして
不自然なcar/ナチュラルにconsして不自然なcar/ナチュラルにconsして
不自然なcar/ナチュラルにconsして
 
Patterns
PatternsPatterns
Patterns
 
Macros in Clojure
Macros in ClojureMacros in Clojure
Macros in Clojure
 
入門ClojureScript
入門ClojureScript入門ClojureScript
入門ClojureScript
 
Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012
 
Clojure的魅力
Clojure的魅力Clojure的魅力
Clojure的魅力
 
Clojure概览
Clojure概览Clojure概览
Clojure概览
 
Stefan Richter - Writing simple, readable and robust code: Examples in Java, ...
Stefan Richter - Writing simple, readable and robust code: Examples in Java, ...Stefan Richter - Writing simple, readable and robust code: Examples in Java, ...
Stefan Richter - Writing simple, readable and robust code: Examples in Java, ...
 
Clojureシンタックスハイライター開発から考えるこれからのlispに必要なもの
Clojureシンタックスハイライター開発から考えるこれからのlispに必要なものClojureシンタックスハイライター開発から考えるこれからのlispに必要なもの
Clojureシンタックスハイライター開発から考えるこれからのlispに必要なもの
 
(map Clojure everyday-tasks)
(map Clojure everyday-tasks)(map Clojure everyday-tasks)
(map Clojure everyday-tasks)
 
Clojure: a LISP for the JVM
Clojure: a LISP for the JVMClojure: a LISP for the JVM
Clojure: a LISP for the JVM
 
Introduction to clojure
Introduction to clojureIntroduction to clojure
Introduction to clojure
 
DSL in Clojure
DSL in ClojureDSL in Clojure
DSL in Clojure
 
プログラミング言語Clojureのニャンパスでの活用事例
プログラミング言語Clojureのニャンパスでの活用事例プログラミング言語Clojureのニャンパスでの活用事例
プログラミング言語Clojureのニャンパスでの活用事例
 
Clojure from ground up
Clojure from ground upClojure from ground up
Clojure from ground up
 

Semelhante a A little exercise with clojure macro

R is a very flexible and powerful programming language, as well as a.pdf
R is a very flexible and powerful programming language, as well as a.pdfR is a very flexible and powerful programming language, as well as a.pdf
R is a very flexible and powerful programming language, as well as a.pdfannikasarees
 
Deep Dive: AWS Command Line Interface
Deep Dive: AWS Command Line InterfaceDeep Dive: AWS Command Line Interface
Deep Dive: AWS Command Line InterfaceAmazon Web Services
 
Super Advanced Python –act1
Super Advanced Python –act1Super Advanced Python –act1
Super Advanced Python –act1Ke Wei Louis
 
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+ConFoo
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Shinya Ohyanagi
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
 
AST - the only true tool for building JavaScript
AST - the only true tool for building JavaScriptAST - the only true tool for building JavaScript
AST - the only true tool for building JavaScriptIngvar Stepanyan
 
Python 내장 함수
Python 내장 함수Python 내장 함수
Python 내장 함수용 최
 
R (Shiny Package) - Server Side Code for Decision Support System
R (Shiny Package) - Server Side Code for Decision Support SystemR (Shiny Package) - Server Side Code for Decision Support System
R (Shiny Package) - Server Side Code for Decision Support SystemMaithreya Chakravarthula
 
Gearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copyGearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copyBrian Aker
 
Gearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copyGearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copyBrian Aker
 
WordPress Cuztom Helper
WordPress Cuztom HelperWordPress Cuztom Helper
WordPress Cuztom Helperslicejack
 
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...Amazon Web Services
 
Designing a database like an archaeologist
Designing a database like an archaeologistDesigning a database like an archaeologist
Designing a database like an archaeologistyoavrubin
 

Semelhante a A little exercise with clojure macro (20)

R is a very flexible and powerful programming language, as well as a.pdf
R is a very flexible and powerful programming language, as well as a.pdfR is a very flexible and powerful programming language, as well as a.pdf
R is a very flexible and powerful programming language, as well as a.pdf
 
Deep Dive: AWS Command Line Interface
Deep Dive: AWS Command Line InterfaceDeep Dive: AWS Command Line Interface
Deep Dive: AWS Command Line Interface
 
Super Advanced Python –act1
Super Advanced Python –act1Super Advanced Python –act1
Super Advanced Python –act1
 
A Shiny Example-- R
A Shiny Example-- RA Shiny Example-- R
A Shiny Example-- R
 
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+Marrow: A Meta-Framework for Python 2.6+ and 3.1+
Marrow: A Meta-Framework for Python 2.6+ and 3.1+
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
AST - the only true tool for building JavaScript
AST - the only true tool for building JavaScriptAST - the only true tool for building JavaScript
AST - the only true tool for building JavaScript
 
Introduction to Groovy
Introduction to GroovyIntroduction to Groovy
Introduction to Groovy
 
Fabric Python Lib
Fabric Python LibFabric Python Lib
Fabric Python Lib
 
Python 내장 함수
Python 내장 함수Python 내장 함수
Python 내장 함수
 
DataMapper
DataMapperDataMapper
DataMapper
 
Django - sql alchemy - jquery
Django - sql alchemy - jqueryDjango - sql alchemy - jquery
Django - sql alchemy - jquery
 
R (Shiny Package) - Server Side Code for Decision Support System
R (Shiny Package) - Server Side Code for Decision Support SystemR (Shiny Package) - Server Side Code for Decision Support System
R (Shiny Package) - Server Side Code for Decision Support System
 
Gearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copyGearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copy
 
Gearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copyGearmam, from the_worker's_perspective copy
Gearmam, from the_worker's_perspective copy
 
WordPress Cuztom Helper
WordPress Cuztom HelperWordPress Cuztom Helper
WordPress Cuztom Helper
 
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...
(BDT401) Big Data Orchestra - Harmony within Data Analysis Tools | AWS re:Inv...
 
Designing a database like an archaeologist
Designing a database like an archaeologistDesigning a database like an archaeologist
Designing a database like an archaeologist
 
Php functions
Php functionsPhp functions
Php functions
 

Último

🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 

Último (20)

🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 

A little exercise with clojure macro

  • 1. A little exercise with Macro Zehua Liu
  • 2. Prerequisites • Basic macro (defmacro mywhen [cond-exp & clauses] `(if ~cond-exp (do ~@clauses))) • Java interop (String. "a string") (.substring "a string" 0 5)
  • 3. Motivation • A script to test a server with a request /response protocol • To send a request to the server, reuse Java classes that represent requests in server code
  • 8. Sending Requests • Many other types of requests • Lots of duplicate codes • Refactor them! • function?
  • 9. Refactor using function (defn send-request [req-pkt sid] (let [[new-sid resp-pkts] (send-req req-pkt sid)] (if-let [err-msg (check-resp-error resp-pkts)] (do (println (format "ERROR: %s failed, sid='%s',req='%s',err='%s'" (.getName req-pkt) sid req-pkt err-msg)) [nil nil]) [new-sid resp-pkts])))
  • 11. Refactor using function • Not too bad • Can we do better / differently? • macro?
  • 13. Make it work for Login Request
  • 14. Make it work for Login Request (defmacro send-request [request username password sid] `(let [req-pkt# (doto (requests.LoginRequest.) (.setUsername ~username) (.setPassword ~password)) [new-sid# resp-pkts#] (send-req req-pkt# ~sid)] (if-let [err-msg# (check-resp-error resp-pkts#)] (do (println (format "ERROR: %s failed, sid='%s',req='%s',err='%s'" ~(name request) ~sid req-pkt# err-msg#)) [nil nil]) [new-sid# resp-pkts#]))) (defn login [:Login username password sid] (send-request username password sid))
  • 15. Make it work for Login Request
  • 16. Make it work for Login Request (defmacro send-request [request username password sid] `(let [req-pkt# (doto (new ~(symbol (str "requests." (name request) "Request"))) (.setUsername ~username) (.setPassword ~password)) [new-sid# resp-pkts#] (send-req req-pkt# ~sid)] (if-let [err-msg# (check-resp-error resp-pkts#)] (do (println (format "ERROR: %s failed, sid='%s',req='%s',err='%s'" ~(name request) ~sid req-pkt# err-msg#)) [nil nil]) [new-sid# resp-pkts#]))) (defn login [username password sid] (send-request :Login username password sid))
  • 17. Make it work for Login Request (.setUsername ~username) <==> (. setUsername ~username) (.setUsername ~username) <==> (. (symbol (str "set" (name :Username))) ~username) (.setUsername ~username) (.setPassword ~password) <==> ~@(map (fn [[pn pv]] `(. ~(symbol (str "set" (name pn))) ~pv)) {:Username username :Password password})
  • 18. Make it work for Login Request (defmacro send-request [request param-map sid] `(let [req-pkt# (doto (new ~(symbol (str "requests." (name request) "Request"))) ~@(map (fn [[pn pv]] `(. ~(symbol (str "set" (name pn))) ~pv)) param-map)) [new-sid# resp-pkts#] (send-req req-pkt# ~sid)] (if-let [err-msg# (check-resp-error resp-pkts#)] (do (println (format "ERROR: %s failed, sid='%s',req='%s',err='%s'" ~(name request) ~sid req-pkt# err-msg#)) [nil nil]) [new-sid# resp-pkts#]))) (defn login [username password sid] (send-request :Login {:Username username :Password password} sid))
  • 19. Refactor using macro (defn login [username password sid] (send-request :Login {:Username username :Password password} sid)) (defn send-message [message dest-username type sid] (send-request :SendMessage {:Message message :DestUsername dest-username :Type type} sid))
  • 20. Refactor using macro • It works! Hooray! • Let’s use it for more fancy stuff. • Optional request fields? • On server side, SendMessage type default to 1, if not specified
  • 21. Optional field (defn send-message [message dest-username type sid] (send-request :SendMessage {:Message message :DestUsername dest-username :Type type} sid)) (defn send-message [message dest-username sid] (send-request :SendMessage {:Message message :DestUsername dest-username} sid))
  • 22. Optional field (defn send-message ([message dest-username sid] (send-message message dest-username nil sid)) ([message dest-username type sid] (let [param-map-base {:Message message :DestUsername dest-username} param-map (if type (assoc param-map-base :Type type) param-map-base)] (send-request :SendMessage param-map sid))))
  • 23. Optional field, FAILED (defn send-message ([message dest-username sid] (send-message message dest-username nil sid)) ([message dest-username type sid] (let [param-map-base {:Message message :DestUsername dest-username} param-map (if type (assoc param-map-base :Type type) param-map-base)] (send-request :SendMessage param-map sid)))) CompilerException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol, compiling: (NO_SOURCE_PATH:10)
  • 25. Optional field, FAILED • macro is evaluated at compile time, not at run time • macro evaluator only knows about symbols – {:Username username :Password password} is a map (keywords to symbols) – But param-map is a symbol – At compile time, macro evaluator does not know the run time value that the symbol param-map represents • How do we fix it?
  • 26. Optional field, Fixing it • How do we fix it? • One thought: – Tell the macro the complete list of fields, and have it generate codes like below for every field: (if-let [v (:Type param-map)] (. setType v)) • And then param-map can be a symbol whose value macro evalutor does not need to know, its value is only needed at run time.
  • 27. Optional field, Fixing it (defmacro send-request [request param-list param-map sid] (let [param-map# param-map r (gensym)] `(let [req-pkt# (let [~r (new ~(symbol (str "requests." (name request) "Request")))] ~@(map (fn [pn] `(if-let [pv# (~pn ~param-map#)] (. ~r ~(symbol (str "set" (name pn))) pv#))) param-list)) [new-sid# resp-pkts#] (send-req req-pkt# ~sid)] (if-let [err-msg# (check-resp-error resp-pkts#)] (do (println (format "ERROR: %s failed, sid='%s',req='%s',err='%s'" ~(name request) ~sid req-pkt# err-msg#)) [nil nil]) [new-sid# resp-pkts#]))))
  • 28. Optional field, Fixing it (defn login [username password sid] (send-request :Login [:Username :Password] {:Username username :Password password} sid)) (defn send-message ([message dest-username sid] (send-message message dest-username nil sid)) ([message dest-username type sid] (let [param-map-base {:Message message :DestUsername dest-username} param-map (if type (assoc param-map-base :Type type) param-map-base)] (send-request :SendMessage [:Message :DestUsername :Type] param-map sid))))
  • 29. Optional field, Fixing it (macroexpand '(send-request :SendMessage [:Message :DestUsername :Type] param-map nil)) (let* [req-pkt__625__auto__ (clojure.core/let [G__671 (new requests.SendMessageRequest)] (clojure.core/if-let [pv__624__auto__ (:Message param-map)] (. G__671 setMessage pv__624__auto__)) (clojure.core/if-let [pv__624__auto__ (:DestUsername param-map)] (. G__671 setDestUsername pv__624__auto__)) (clojure.core/if-let [pv__624__auto__ (:Type param-map)] (. G__671 setType pv__624__auto__))) vec__672 (scratch.core/send-req req-pkt__625__auto__ nil) new-sid__626__auto__ (clojure.core/nth vec__672 0 nil) resp-pkts__627__auto__ (clojure.core/nth vec__672 1 nil)] (clojure.core/if-let [err-msg__628__auto__ (scratch.core/check-resp-error resp-pkts__627__auto__)] (do (clojure.core/println (clojure.core/format "ERROR: %s failed, sid='%s',req='%s',err='%s'" "SendMessage" nil req-pkt__625__auto__ err-msg__628__auto__)) [nil nil]) [new-sid__626__auto__ resp-pkts__627__auto__]))
  • 30. Lessons Learned • macro is evaluated at compile time, not at run time • macro evaluator treats code as data – {:Username username :Password password} is a map of keywords to symbols, not keywrods to strings (or whatever type username/password might be) – But param-map is a symbol • At compile time, macro evaluator treats ref/var as symbol, knowing nothing about their run time values