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.