Ken Wesson <kwess...@gmail.com> writes: Hi Ken!
>> That somehow makes sense, but is there some way to get the complete >> map with defaults applied, too? > > (defn foo > [{:keys [a b] > :or {a 1 b 2} > :as all}] > (let [all (merge {:a 1 :b 2} all)] > [(hash-map :a a :b b) all])) > > Of course this repeats the map of defaults, so this is ugly and will > get unwieldy if the default map gets much bigger. Yep. > Some macro-fu can no doubt help: > > (defn keysm [m] > (zipmap (map #(keyword (name %)) (keys m)) (vals m))) > > (defmacro defnm [name argvec & body] > `(defn ~name ~argvec > (let ~(vec > (apply concat > (for [a argvec :when (and (map? a) (:or a) (:as a))] > [(:as a) `(merge ~(keysm (:or a)) ~(:as a))]))) > ~@body))) > > (defnm bar > [{:keys [a b] > :or {a 1 b 2} > :as all}] > [(hash-map :a a :b b) all]) > > (defnm baz > [{:keys [a b] > :or {a 1 b 2} > :as all} quux] > [(hash-map :a a :b b) all quux]) > > (defnm quux > [{:keys [a b] > :or {a 1 b 2} > :as all} > {:keys [c d] > :or {c 3} > :as all2}] > [(hash-map :a a :b b :c c :d d) all all2]) > > => (foo {}) > [{:a 1, :b 2} {}] > => (bar {}) > [{:a 1, :b 2} {:b 2, :a 1}] > => (baz {} 3) > [{:a 1, :b 2} {:b 2, :a 1} 3] > => (quux {} {}) > [{:a 1, :c 3, :b 2, :d nil} {:b 2, :a 1} {:c 3}] > => (quux {:b 3} {}) > [{:a 1, :c 3, :b 3, :d nil} {:b 3, :a 1} {:c 3}] Hey, that's pretty nice. :-) > Caveats: > > 1. As you can see, the sequence of keys can be rearranged between the > two maps. But you shouldn't be relying on key order anyway with > unsorted maps. I don't. > 2. This bare-bones macro doesn't handle docstrings on the functions. That's bad. But for my use-case, the docstrings are mandatory, so I can easily add them to your macro. > 3. Map destructuring nested in some other destructuring form won't get > the special treatment; only at the top level. Nobody would understand that anyway. ;-) > 4. You can't mix both behaviors of :as in the same function with > different destructured map arguments, other than by nesting the one > where you want the old :as behavior in some other destructuring form. Yes, sure. > But it should cover the very common case of an undocumented (internal) > function with a single map parameter to destructure, and with a little > tweaking could be extended to handle docstrings properly. Well, in my case the frontend function does that destructuring and the undocumented internal function expects correct arguments, because then the user can see the defaults in the docs. Isn't that a common use-case which would justify adding a new map destructuring key to the clojure core? Something like (fn [{:keys [a b c] :or {b 0, c 17} :as given :giving result}] [given result]) with :as being the current behavior and :giving the same result as :as in your defnm macro. (Actually, :giving is not a good name. Native speakers to the front...) Bye, Tassilo -- 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