I’m kicking myself as I have exactly that book but it got lost in the ‘TODO’ 
pile.

> On 2 Oct 2015, at 13:31, Jason Stewart <jstew...@fusionary.com> wrote:
> 
> "Mastering Clojure Macros" by Colin Jones gets my vote as the go to book for 
> writing clojure macros.
> 
> 
> On Fri, Oct 2, 2015 at 8:24 AM, Colin Yates <colin.ya...@gmail.com 
> <mailto:colin.ya...@gmail.com>> wrote:
> Thanks for your comments - very helpful!
> 
> The reference to destructuring might be irrelevant now. Previously I noticed 
> that the _map construction_ was emitted from the macro rather than the symbol 
> bound to the map. For example, some variation of quoting meant (defmacro a 
> [m] (println m)) called with (a {:1 1}) emitted (println {:1 1}) rather than 
> (println m). Now I think about it is because an earlier iteration of the 
> macro used ~m - I’m not at the desk so I can’t confirm.
> 
> Any pointers a decent Clojure macro book? I found lots of blogs around from 
> google but not a single one of them mentioned the (let [m-state (gensym)] 
> `(let [~m-state ~state])) ‘trick’.
> 
> Thanks again.
> 
>> On 2 Oct 2015, at 10:50, gianluca torta <giato...@gmail.com 
>> <mailto:giato...@gmail.com>> wrote:
>> 
>> Hi Colin,
>> 
>> as far as I can tell, your solution looks fine... here are a couple of 
>> comments on your step-by-step analysis
>> 
>> cheers,
>> Gianluca
>> 
>> 
>> 1(defmacro form [state & elements]
>> 2  (let [m-state (gensym)]
>> 3    `(let [~m-state ~state]
>> 4       [:div.form.horizontal
>> 5        ~@(map (fn [[f m & rest]]
>> 6                 `[~f (assoc ~m
>> 7                             :value (get @(:values ~m-state) (:id ~m))
>> 8                             :on-change #(swap! (:values ~m-state) assoc 
>> (:id ~m) "UPDATED"))
>> 9                   ~@rest])
>> 10               elements)])))
>> 
>> 0 - ` means "emit, don't evaluate", ~@ means "splice, e.g. remove the outer 
>> sequence so [a ~@[1 2]] becomes [a 1 2] and ' means 'the symbol of rather 
>> than the value of'.
>> ~@ means "evaluate and splice", i.e., it overrides the "don't evaluate" of ` 
>> and splices the result in the outer sequence
>> ~ means just "evaluate" without the splicing
>>  
>> 2 - declare m-state, which is lexically scoped to the macro and is bound to 
>> a random identifier created by gensym
>> 3 - the back-tick (syntax-quote) returns the form rather than evaluating the 
>> form, so the macro will return (let* [m-8_324230_ ....]) The [~m-state 
>> ~state] is just bewildering though.
>> 3 - in addition, the 'state' argument appears to be destructured, but only 
>> to one level so if the state contains an atom it is the var of the atom
>> 'state' is evaluated due to ~, not sure what you mean by 'destructured, but 
>> only to one level'
>>  
>> 4 - literal text emitted in-line
>> 5 - splice the results of the map (i.e. rather than [:div.form.horizontal 
>> [child1 child2]] return [:div.form.horizontal child1 child2])
>> 5 - also destructure each element assuming [f m(ap) and 0 or more other args]
>> yes, the destructuring is just a normal destructuring of the args passed to 
>> the fn by map
>>  
>> 6 - emit [<f> where <f> is the first symbol, 'f' l in each element. Also 
>> prevent this being evaluated in the macro with the syntax-quote as (5) has 
>> introduced some new scope because of the ~@ - not sure.
>> as said above, rather than introducing a new scope, ~@ just overrides the 
>> "don't evaluate" of back-tick
>>  
>> 6 - also associate onto the symbol m (which is assumed to be associative, 
>> e.g. a map)...
>> 7/8 - extract data out of the 'run-time' (e.g. not macro-time) value of the 
>> provided state (magically captured under ~m-state)
>> 9 - splice in the rest of the arguments, if any, that were part of the 
>> element
>> 10 - and do that magic for each element
>>  
>> 
>> -- 
>> You received this message because you are subscribed to the Google
>> Groups "Clojure" group.
>> To post to this group, send email to clojure@googlegroups.com 
>> <mailto:clojure@googlegroups.com>
>> Note that posts from new members are moderated - please be patient with your 
>> first post.
>> To unsubscribe from this group, send email to
>> clojure+unsubscr...@googlegroups.com 
>> <mailto:clojure+unsubscr...@googlegroups.com>
>> For more options, visit this group at
>> http://groups.google.com/group/clojure?hl=en 
>> <http://groups.google.com/group/clojure?hl=en>
>> --- 
>> You received this message because you are subscribed to the Google Groups 
>> "Clojure" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to clojure+unsubscr...@googlegroups.com 
>> <mailto:clojure+unsubscr...@googlegroups.com>.
>> For more options, visit https://groups.google.com/d/optout 
>> <https://groups.google.com/d/optout>.
> 
> 
> -- 
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com 
> <mailto:clojure@googlegroups.com>
> Note that posts from new members are moderated - please be patient with your 
> first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com 
> <mailto:clojure%2bunsubscr...@googlegroups.com>
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en 
> <http://groups.google.com/group/clojure?hl=en>
> --- 
> You received this message because you are subscribed to the Google Groups 
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to clojure+unsubscr...@googlegroups.com 
> <mailto:clojure+unsubscr...@googlegroups.com>.
> For more options, visit https://groups.google.com/d/optout 
> <https://groups.google.com/d/optout>.
> 
> 
> -- 
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with your 
> first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en 
> <http://groups.google.com/group/clojure?hl=en>
> --- 
> You received this message because you are subscribed to the Google Groups 
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to clojure+unsubscr...@googlegroups.com 
> <mailto:clojure+unsubscr...@googlegroups.com>.
> For more options, visit https://groups.google.com/d/optout 
> <https://groups.google.com/d/optout>.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to