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 <[email protected]> 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 [email protected]
> Note that posts from new members are moderated - please be patient with your
> first post.
> To unsubscribe from this group, send email to
> [email protected]
> 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 [email protected]
> <mailto:[email protected]>.
> 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 [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
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 [email protected].
For more options, visit https://groups.google.com/d/optout.