1. Looks like everyone prefers the let-kw name. Sounds good to me.
2. I tried it with the more let-like form, but I don't like the number
of opening braces required. For a full kw-spec, the form would end up
(let-kw [[[:kw default supplied?]] kw-args] ...). Clojure tends to err
on the side of fewer braces and parentheses, and three opening braces
looks excessive to me. That said, I see the point of keeping it
consistent with the other binding forms.
3. Unnecessary interleave replaced with zipmap.
4. With regard to the generality of the interface: I put all those
features in there because I have wanted to use them. I often find
myself writing or wrapping API-like code, and slicing and dicing
arguments and passing them through to other functions, as vectors or
maps, has been useful.
5. As for putting the macro in clojure-contrib, thanks for the vote of
confidence. :) I'll drop a signed Contributor Agreement in the mail
today, and get an Assembla ticket and patch out soon.
Thanks for all the feedback and suggestions. New version:
(defmacro let-kw
"Adds flexible keyword handling to any form which has a parameter
list: fn, defn, defmethod, letfn, and others. Keywords may be
passed
to the surrounding form as & rest arguments, lists, or maps. Lists
or
maps must be used for functions with multiple arities if more than
one arity has keyword parameters. Keywords are bound inside let-kw
as
symbols, with default values either specified in the keyword spec
or
nil. Keyword specs may consist of just the bare keyword, which
defaults to nil, or may have the general form [:keyword-name
keyword-default-value* keyword-supplied?*]. keyword-supplied? is
an
optional symbol bound to true if the keyword was supplied, and to
false otherwise."
[kw-spec-raw kw-args & body]
(let [kw-spec (map #(if (sequential? %) % [%]) kw-spec-raw)
keywords (map first kw-spec)
symbols (map (comp symbol name) keywords)
defaults (map second kw-spec)
destrmap {:keys (vec symbols) :or (zipmap symbols defaults)}
supplied (reduce
(fn [m [k v]] (assoc m k v)) (sorted-map)
(remove (fn [[_ val]] (nil? val))
(partition 2 (interleave keywords
(map (comp second
rest)
kw-spec)))))
kw-args-map (gensym)]
`(let [kw-args# ~kw-args
~kw-args-map (if (map? kw-args#)
kw-args#
(apply hash-map kw-args#))
~destrmap ~kw-args-map]
~@(if (empty? supplied)
body
`((apply (fn [~@(vals supplied)]
~...@body)
(map (fn [x#] (contains? ~kw-args-map x#))
[~@(keys supplied)])))))))
--
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