The writing of Clojure/Script macro may seem as a wizard senior craft, but this article will show you that it's not the case. This is the second part of my journey to learn Clojure/Script macro and this article will deal with Clojure macro. programming Motivation In the , I exposed my issue which is illustrated by this snippet: part I article of this serie ( add-bubble [appstate bubble] ( appstate conj bubble)) ( add-bubble! [bubble] ( appstate ( [appstate_arg] ( appstate_arg bubble)))) defn- update :bubbles defn swap! fn add-bubble I would like to write a macro, let say , which will take the function as argument and generate the function which is the side-effect version of it. BANG add-bubble add-bubble! Even if my goal is to write ClojureScript macro, I like to go one step after another, thus I thought it is a good idea to learn how to write Clojure macro first. ClojureScript takes its origin from Clojure, and from my experience in programming, it's easier to build from solid basics rather than eagerly jump to the last step. Also from my experience, you usually get more documentation/ressources from the root language than its derivative. Macro: the origin During my try/error process in learning macro, I was wondering: where does this idea of macro came from? As Clojure is known to be a dialect of Lisp, the path to its origin is clear. Lisp was invented by and its team in the late 1950s at MIT. At this time, FORTRAN was really the main programming language used on the early years of IBM machines. When McCarthy discovered the FORTRAN language, he was fascinated by the idea of writing programs with "algebraic" means. But as his main topic was Artificial Intelligence, he was also convinced of the need of a different way to express a program to a computer. John McCarthy Another programming language which would allow to handle symbolic expressions. These thought lead him to create the LISP . If you're interested by the history of LISP language, I recommend you where you'll get the historical context of McCarthy's work as well as the atmosphere at this time between the machine builder, the compiler builder and R&D interests (read funding). From this article: language this article of Herbert Stoyan Already in 1956 it was clear that one had to work with symbolic expressions to reach the goal of artificial intelligence. As the researchers already understood numerical computation would not have much importance. McCarthy, in his aim to express simple, short description parts by short language elements, saw the composition of algebraic sub-expressions as an ideal way to reach this goal. In , you can find a list of 24 new ideas for programming language (at this time) from McCarthy. I quote here some idea which are the essence of macro in my humble opinion: this related article still of Herbert Stoyan (4) extensibility of programs (incremental compiler) and changeability of programs, (10) possibilities for manipulating symbolic quantities. Rich Hickey, the author and maintainer of Clojure, has recently published an article titled . This article explained his motivations around Clojure, some design choice he has made in the language, and obviously discuss about similarities and differences between LISP and Clojure. "A History of Clojure" On the topic of macro, Clojure macros are similar to Common Lisp macros. One difference discussed is about how symbol are manipulated by these two languages. In Clojure symbols are essentially simple names: their resolution to a value can be delayed. As long as you don't required the value behind a symbol, you don't know if a symbol is bound a to value, or from where its potential value come from. During the talk , Rich Hickey said about Clojure macro: "Clojure for Lisp Programmers" macros are manipulating this name-world not this var-world Finally, when I was looking for more documentation about macro, I discovered there are two kinds of macro: the regular ones and . are special/low level syntax in Clojure . For example, the quote operator, . Its use indicates to the Clojure reader to avoid the evaluation step of the form which follows the quote operator. reader macros Reader macros code ' For example, expression will produce the symbol : Clojure doesn't attempt to resolve the potential value behind the name . For me the constitutes the foundation of the language itself, and in Clojure whereas it is possible to do so in LISP. 'foo foo foo reader macro the user cannot define new reader macros From this point, the term will always refer to regular macro. macro Macro: a "blur" definition To handle new concept, it's useful to take a look at the definition of the concept. So here is my definition of Clojure macro: Clojure macros are code that generate code. That's it. Thanks for coming. I'm joking, please bear with me. You'll find a more convincing definition from : the official home page of Clojure Clojure has a programmatic macro system which allows the compiler to be extended by user code. Macros can be used to define syntactic constructs which would require primitives or built-in support in other languages. Many core constructs of Clojure are not, in fact, primitives, but are normal macros. It's (almost) always simpler for me to look at a concrete example and then reason about it. Let's look at the macro provided by namespace: when clojure.core ( when) source ;; => (defmacro when ;; "Evaluates test. If logical true, evaluates body in an implicit do." ;; {:added "1.0"} ;; [test & body] ;; (list 'if test (cons 'do body))) At first sight, the definition of the macro is very similar to the definition of a regular function except the use of the keyword instead of . Roughly, the macro definition skeleton is: when defmacro defn ( <macro-name> <documentation-string> <meta-data> <argument-list> <body>) defmacro For completeness, here is a simple example of the code generated by on a simple example: when ( '( )) => ( ( )) macroexpand when true 42 if true do 42 The function is especially useful to check the generated code from a given macro. From this first observation, some thoughts can immerge. macroexpand The first fundamental difference between macro code and regular code is that macro code is executed at compile time. Which means, before the writing of Java bytecode by the Clojure compiler, which will be effectively translated to Java bytecode. macros have to be to get the terminal Clojure code expanded The second main difference is that the arguments of macro are not evaluated: they remain symbols in the body of macro. In the subsequent part of this article, a particular emphasis on this point will be made. Macro is the tool . Wikipedia defines metaprogramming as: to do metaprogramming Metaprogramming is a programming technique in which computer programs have the ability to treat other programs as their data. Clojure macro takes as input any Clojure data and generates arbitrary Clojure code: full power. The talk introduces Clojure macro as a hook to the compiler. Macros are expanded/executed at compile time; it's relevant to see them as extension to the compiler: it allows you to define new syntax. "Illuminated Macros" Build the BANG macro This article don't have the pretension to learn you how to write Clojure macro. Many high quality materials are available online. If you want to master the craft of creating macro and decipher all notations it involves, you should read one of these links: Writing Macros -- Clojure for the Brave and True Macros -- Clojure from the ground up Macros -- The Joy of Clojure With only one of these resources, you'll feel fluent to write Clojure macro by the end of the day. By learning it, the main difficulty I experienced is to understand when to keep a symbol as is, instead of taking it's value in the macro body . Back to my use case, I want to create a macro to generate the side effect version of a function which change the state of my application (cf the snippet at the top of this article). To achieve this, here is first attempt: ( BANG [func-name] ( [func-name-banged ( ( func-name )) arg-symbol ( ( )) appstate-arg-symbol ( ( ))] `( ~func-name-banged [~arg-symbol] ( appstate ( [~appstate-arg-symbol] (~func-name ~appstate-arg-symbol ~arg-symbol)))))) defmacro "Define the side-effect version of a given function 'func-name'" let symbol str "!" symbol str "arg" symbol str "appstate-arg" defn swap! fn Writing macros is generally not as easy as developing regular function. Along the road, I intensively use the function which takes a form as input and gives back the full expansion of it: macroexpand ( '( add-bubble)) macroexpand BANG ;; => (def add-bubble! ;; (clojure.core/fn ;; ([arg] ;; (clojure.core/swap! core/appstate ;; (clojure.core/fn [appstate-arg] ;; (add-bubble appstate-arg arg)))))) As many Clojure instructions rely on macros, the result of can be a bit confusing. As does recursively all macro expansions, some implementation detail of builtin functions is exposed and this is generally not relevant when you write your own macro. To hide this complexity, you can use instead as it does only one step of macro expansion: macroexpand macroexpand macroexpand-1 ( '( add-bubble)) macroexpand-1 BANG ;; => (clojure.core/defn add-bubble! [arg] ;; (clojure.core/swap! core/appstate ;; (clojure.core/fn [appstate-arg] ;; (add-bubble appstate-arg arg)))) The form expanded correctly to the target function definition : it works! (BANG add-bubble) add-bubble! To comment briefly the body of macro, firstly you can see the binding of to . The function allows you to . In Clojure, a is bound or not to a (a is basically a value). Through the call , stores a symbol with the name "add-bubble!": BANG func-name-banged (symbol (str func-name "!")) symbol create a symbol from an arbitrary string Symbol Var Var (BANG add-bubble) func-name-banged ( ( )) ( ( ( ))) ( ( ( ))) ( ( ( ( )))) symbol str "add-bubble" "!" ;; => add-bubble! type symbol str "add-bubble" "!" ;; => clojure.lang.Symbol name symbol str "add-bubble" "!" ;; => "add-bubble!" type name symbol str "add-bubble" "!" ;; => java.lang.String Secondly, you can see local variables and which just store a symbol with a given name. In the body of the macro, these variables are used in the signature of functions and you can see in the macro expansion that the compiler resolves them just with there name (the string provided at their initialisation). arg-symbol appstate-arg-symbol This is a way to manage situation where you want to use a free variable in a macro. A free variable is not bound (yet) to a value during the macro compilation, which is on purpose as the BANG macro generate a function, and so its signature. As this situation is recurrent, you can also use the function which returns a symbol with a unique name. If you rewrite the macro using the function, you'll get: gensym BANG gensym ( BANG [func-name] ( [func-name-banged ( ( func-name )) arg-symbol ( ) appstate-arg-symbol ( )] `( ~func-name-banged [~arg-symbol] ( appstate ( [~appstate-arg-symbol] (~func-name ~appstate-arg-symbol ~arg-symbol)))))) ( '( add-bubble)) defmacro "Define the side-effect version of a given function 'func-name'" let symbol str "!" gensym gensym defn swap! fn macroexpand-1 BANG ;; => (clojure.core/defn add-bubble! [G__7657] ;; (clojure.core/swap! core/appstate ;; (clojure.core/fn [G__7658] ;; (add-bubble G__7658 G__7657)))) You can see that is expanded to and to . This version of is completely equivalent to the previous one with less characters and also a bit less readable when you look at the macro expansion. If you don't care about a particular name behind a symbol, the use of is perfectly fine. arg-symbol G__7657 appstate-arg-symbol G__7658 BANG gensym If you want to learn more about the use of generated symbols, I recommend which also gives a lot of material about the use of macro itself. this article In this article, I prefer to have a macro with an easy macro expansion to comment, so I'll stick with the first version of it. BANG The current definition of macro works perfectly for the function, but its not generic enough for my application. I have other functions which take more than one argument as input, not just one. The number of arguments accepted as input by a function is called in Clojure. BANG add-bubble arity The function need only one argument: the bubble to add to the global state . But what if the function I deal with takes more than one argument as input. For example the function takes 2 arguments as input: a bubble-id and an hashmap of attributes to update a given bubble. add-bubble! appstate update-bubble The big deal here is to find a mechanism to retrieve the number of argument(s) of the input function passed to the macro. Another formulation would be: "How to deal with functions of arbitrary arity with the macro?". BANG BANG All the magic of Clojure macros lives in the fact that you can access to thins kind of information at compile time: the programmer has the power to handle them at his/her convenience. Handle n-arity by the BANG macro A really interesting feature of Clojure for me is the accessibility to metadata information. Every time you define a variable through , some metadata is automatically attach to this variable. def The describes the standard information that are defined and their meaning. You can inspect these metadata with function: official documentation meta ( ( add-bubble)) ( ( add-bubble)) type var ;; => clojure.lang.Var meta var ;; => {:private true, ;; :arglists ([appstate bubble]), ;; :line 12, ;; :column 1, ;; :file ".../clojurescript macro not so long journey/part2/appstate/src/appstate.clj", ;; :name add-bubble, ;; :ns #namespace[core]} You can call only on a value of type . To get a from a , you just have to use the var function. Its documentation says: meta Var Var Symbol ( var) doc ;; => var ;; (var symbol) ;; Special Form ;; The symbol must resolve to a var, and the Var object ;; itself (not its value) is returned. The reader macro #'x expands to (var x). ;; ;; Please see http://clojure.org/special_forms#var ;; The symbol must resolve to a var, and the Var object ;; itself (not its value) is returned. The reader macro #'x expands to (var x). What really interested me in metadata data information is the field as it gives you the list of input argument for a given function, exactly what I need to handle function of any arity within the macro. Every function without side effect take the current application state, , as first argument. To generate the side effect of them, I need their signature without the first argument: :arglists BANG appstate ( add-bubble var meta first rest) -> :arglists ;; => (bubble) Voila, now I just need to update the macro, and we'll be ready to wrap up everything: BANG ( BANG [func-name] ( [func-name-banged ( ( func-name )) appstate-arg-symbol ( ) func-var ( func-name) arg-list ( func-var meta first rest) ] `( ~func-name-banged [~@arg-list] ( appstate ( [~appstate-arg-symbol] (~func-name ~appstate-arg-symbol ~@arg-list)))) )) defmacro "Define the side-effect version of a given function 'func-name'" let symbol str "!" symbol "appstate-arg" var -> :arglists defn swap! fn But when I compiled this macro, I get a weird and mysterious error message: 1. Caused by java.lang.RuntimeException Unable to resolve var: func-name in this context For an unknown reason, I cannot call the function in a macro definition. After tinkering the code for a moment, I got more error just as mysterious as each other. var At this point, I understood my vision of the puzzle was not complete, something was missing and I had to dig deeper or ask for help. Some moment later, I found which is relative to my issue. This question is about getting a var value in the body of a macro. Especially, in the given answer, a function , that I were not aware of, is used. Let's take a look at the documentation of this function: this question on stackoverflow resolve ( resolve) ( ns-resolve) doc ;; => clojure.core/resolve ;; ([sym] [env sym]) ;; same as (ns-resolve *ns* symbol) or (ns-resolve *ns* &env symbol) doc ;; => clojure.core/ns-resolve ;; ([ns sym] [ns env sym]) ;; Returns the var or Class to which a symbol will be resolved in the ;; namespace (unless found in the environment), else nil. Note that ;; if the symbol is fully qualified, the var/Class to which it resolves ;; need not be present in the namespace. From a given , the function look up a in the namespace from where it is called. In fact, this is what I needed for my macro. To convince myself of the good behaviour of the this function, I like to write dummy examples: Symbol resolve Var BANG ( dummy-arg ) ( dummy-m [arg] ( arg)) ( '( dummy-m [arg] ( arg))) ( dummy-arg) def 42 defmacro resolve macroexpand defmacro resolve ;; => (do ;; (clojure.core/defn dummy-m ([&form &env arg] (resolve arg))) ;; (. #'m (setMacro)) ;; #'m) dummy-m ;; => #'core/dummy-arg What is interesting is the above snippet is the expansion of the definition of the macro. You can see the use of special arguments and . You can use to see how a macro has been called: dummy-m &form &env &form ( dummy-m1 [arg] ( &form)) ( ( doesn't-exist)) defmacro prn dummy-m1 + 3 2 ;; => (dummy-m1 (+ 3 2 doesn't-exist)) The variable let you inspect the current compiler environment for the macro: &env ( dummy-m2 [] ( &env)) ( ) defmacro prn dummy-m2 ;; => nil By default, the variable is nil. This is not the main track of this article, so if you want to learn more about it, I recommend . Anyway, the only point I would like to emphasize here is that Clojure macro is definitely a hook to the Clojure compiler and this tiny examples give you some hint on how you can tackle this topic. &env this article Finally, to fix the macro, I have to use the function instead of : BANG resolve var ( BANG [func-name] ( [func-name-banged ( ( func-name )) appstate-arg-symbol ( ) func-var ( func-name) arg-list ( func-var meta first rest)] `( ~func-name-banged [~@arg-list] ( appstate ( [~appstate-arg-symbol] (~func-name ~appstate-arg-symbol ~@arg-list)))) )) ( '( add-bubble)) defmacro "Define the side-effect version of a given function 'func-name'" let symbol str "!" symbol "appstate-arg" resolve -> :arglists defn swap! fn macroexpand-1 BANG ;; => (clojure.core/defn add-bubble! [bubble] ;; (clojure.core/swap! core/appstate ;; (clojure.core/fn [appstate-arg] ;; (add-bubble appstate-arg bubble)))) The macro can now handle functions of any arity. BANG Conclusion Clojure macro is really a powerful feature: it allows you generate arbitrary code from Clojure data. But as you saw through this article, it can be a bit sporty to get it works, the way you want. Except for the trick, there are really good materials around the Clojure macro feature in different books/blog posts and as I said, after reading one of this documentation you'll be comfortable to write your own macro by the end of the day. resolve Learning Clojure macro was a preliminary step to tackle serenely the ClojureScript macro feature. Some subtle differences exist between those two but this is another story that I'll go through in the last article of this serie.