Why doesn't LET work with VECTOR?
The let special form The required form must be a vector literal, not just an expression that evaluates to a vector.
Why? Roughly speaking, an expression must be compiled before it can be evaluated. At compile time , it will (vector x 1)
not evaluate to before vector
, it will just be a list. Indeed, if it were evaluated, the arguments vector
would be evaluated, which would mean that x
it would have to be resolved. But you don't want to x
be allowed, you want to be bound.
source to share
Look at the source for the macrolet
(defmacro let
"binding => binding-form init-expr
Evaluates the exprs in a lexical context in which the symbols in
the binding-forms are bound to their respective init-exprs or parts
therein."
{:added "1.0", :special-form true, :forms '[(let [bindings*] exprs*)]}
[bindings & body]
(assert-args let
(vector? bindings) "a vector for its binding"
(even? (count bindings)) "an even number of forms in binding vector")
`(let* ~(destructure bindings) ~@body))
You will notice that the argument is bindings
not evaluated when the macro tries to ensure that the correct arguments have been supplied to it via assert-args
.
At the moment when clojure estimates (vector? bindings)
, bindings
- a form of ( list
) comprising fn
, as a first element, followed by arguments and, therefore, is not vector
at this point.
source to share
let
a vector is required for bindings (at compile time), so trying to put the vector function call in its place won't work (as it will only result in a vector at runtime).
However, you can make your own with a bit of macro fu:
(defmacro mylet [bindings & exprs]
`(let ~(vec bindings) ~@exprs))
(mylet (x 1) (inc x))
=> 2
source to share