On Thu, Jun 16, 2011 at 9:51 AM, Tassilo Horn <tass...@member.fsf.org> wrote: > Hi all, > > I have some functions that use destructuring on a map parameter, and it > seems I have a false assumption on the workings. Take for example this > one: > > (defn foo > [{:keys [a b] > :or {a 1 b 2} > :as all}] > [(hash-map :a a :b b) all]) > > I expected it to always return a vector of two equal maps. However, > that's not true. all is in fact the map I gave at the call, not the map > with the default values declared in the :or applied. > > Why is that? So that you can distinguish given actual args that happen > to match default values from real, non-given defaults? > > 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. 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}] 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. 2. This bare-bones macro doesn't handle docstrings on the functions. 3. Map destructuring nested in some other destructuring form won't get the special treatment; only at the top level. 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. 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. > > In my application, I don't care about if some value is an implicit or > explicit default, but I have some functions with many keys that are > split in two subfunctions. One public frontend functions with :or in > order to let callers see the defaults, and one private function that > does the actual work, assumes correct args and is called by the public > one: > > (defn- foo-1 [{:keys [a b c]}] ...) > > (def foo [{:keys [a b c] > :or {a 1 b 2 c 3} > :as all}] > ;; do some stuff > ;; (foo-1 all) ;; That won't work, instead I have to do the lengthy... > (foo-1 (hash-map :a a :b b :c c)) > ;; do more stuff > ) > > Any recourse? > > 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 -- Protege: What is this seething mass of parentheses?! Master: Your father's Lisp REPL. This is the language of a true hacker. Not as clumsy or random as C++; a language for a more civilized age. -- 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