Clojure
user=> (def a)
#'user/a
user=> (def b)
#'user/b
user=> (binding [[a b] [1 2]] (+ a b))
java.lang.ClassCastException: clojure.lang.LazilyPersistentVector cannot be cast to clojure.lang.Symbol (NO_SOURCE_FILE:3)
user=>
If it's feasible, it's a feature I'd like to see in Clojure at some point.
It looks like tagging the gensym'd symbols with metadata will work. I'm having a go at it.
This is code from my socket repl that sparked my interest in support
for destructuring in clojure/binding.
(defn socket-streams ;; returns a vector of 3 streams
[s]
[(LineNumberingPushbackReader. (InputStreamReader. (.getInputStream
s) "UTF-8"))
(OutputStreamWriter. (.getOutputStream s) "UTF-8")
(PrintWriter. (OutputStreamWriter. (.getOutputStream s) "UTF-8")
true)])
(defn socket-repl ;; accepts a vector of 3 streams with minimal
fuss
"Starts a repl thread on the iostreams of supplied socket"
[s]
(on-thread
#(binding [[*in* *out* *err*] (socket-streams s)] (SocketRepl/
repl))))
I've updated the patch I posted previously. I think this
implementation is very readable and a nice example of how much
destructuring, metadata, and reader support for a variety of
collections can contribute to making Clojure code more clear and
compact.
http://clojure.googlegroups.com/web/destructuring-binding.patch
Please consider including it in Clojure.
Thanks,
--Steve
> Hello Stephen.
>
> I am not sure I understand. Your example doesn't seem to suggest that
> you are really needing a form of destructuring. Rather, it looks like
> multiple bindings. Presently, I can do:
>
> krukow:~/languages/clojure/trunk$ cl
> Clojure
> user=> (def a)
> #'user/a
> user=> (def b)
> #'user/b
> user=> (binding [a 1 b 2] (+ a b))
> 3
> user=>
>
> Would that be enough?
Hi Karl,
You're right, the example I gave was simplified to the point where it
could be done as you've shown.
Other binding forms in Clojure (fn arguments, let, loop) support some
very nice destructuring features -- names can be bound to parts of
"sequential things" or parts of "associative things" in a very
flexible and readable way.
My patch allows those same features to be used with vars in binding.
One of the nice uses of Clojure's destructuring is to provide most of
the benefit of returning multiple values from a function without
straying from the Java calling convention of a single return value--a
function can pass back a vector, but the caller can still end up with
names for each of the components easily.
Here's a simplified version of a better example from a later posting:
(defn socket-streams ;; returns a vector of 3 streams
[s]
[(InputStreamReader. (.getInputStream s) "UTF-8"))
(OutputStreamWriter. (.getOutputStream s) "UTF-8")
(OutputStreamWriter. (.getOutputStream s) "UTF-8") )])
(defn socket-user ;; binds the vector of 3 streams to vars with
minimal fuss
"Use the iostreams of a supplied socket"
[s]
(on-thread
#(binding [[*ins* *outs* *errs*] (socket-streams s)]
(stream-using-func))))
This could be done right now with a let to do the destructuring and a
bind to the individual values to vars, but my patch makes that
unnecessary/automatic and makes all Clojure binding forms consistent
in supporting destructuring.
Cheers,
--Steve