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 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

Reply via email to