Daniel Kaplan
Daniel Kaplan

Reputation: 67300

Is it possible to destructure a map in a bind?

Is it possible to do this in one function:

(binding [*configs* (merge default-configs configs)]
    (let [{:keys [login url max-pages]} *configs*]
      ..

When I tried this:

(binding [{:keys [login url max-pages] :as *configs*} (merge default-configs configs)]

It gave me this error:

CompilerException java.lang.ClassCastException: clojure.lang.PersistentArrayMap cannot be cast to clojure.lang.Symbol

A little googling showed me that Common Lisp has a function called destructure-bind but I'm not sure if that's related.

Upvotes: 0

Views: 302

Answers (2)

Michał Marczyk
Michał Marczyk

Reputation: 84331

No, nothing like this will work with core macros.

The reason is that both binding and let (and friends, e.g. with-bindings) do just one thing. In the case of binding, that thing is installing thread-local bindings for Vars; for let, it is introducing local bindings. These are entirely different operations.

In let, destructuring has a clear meaning: it introduces new locals, which is exactly what the basic, non-destructuring let bindings do. This is also clearly useful, as prying appart data structures and binding different parts to different locals is a common need. The names of the locals are also locally determined, so things like :keys in associative destructuring work well.

In binding, to be consistent with its main purpose, destructuring would need to bind several Vars simultaneously to several parts of a data structure. This is not nearly as useful. If instead destructuring in binding were to introduce locals, then all of a sudden binding would do two unrelated things, possibly both in the same binding pair (note how the failing binding form from the question text expects the bindings introduced by :keys to be locals, but the binding made by :as to be the usual thread-local binding of a Var). Thus binding simply opts not to support destructuring. (If you need to bind parts of a data structure to several Vars, you can use a let to perform the destructuring, then install the bindings with binding.)


As for destructuring-bind, it's basically the destructuring-enabled version of let in Common Lisp. CL's let does not support destructuring.

Upvotes: 2

mobyte
mobyte

Reputation: 3752

"Binding Forms (Destructuring)" section:

Clojure supports abstract structural binding, often called destructuring, in let binding lists, fn parameter lists, and any macro that expands into a let or fn. ...

AFAIK binding itself doesn't use destructuring mechanism (via fn of let).

Upvotes: 1

Related Questions