On Thu, Jun 16, 2011 at 9:51 AM, Tassilo Horn <[email protected]> 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 [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
--
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 [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