Why doesn't LET work with VECTOR?

Instead

(let [x 1] (my-expression))

      

I am trying to use:

(let (vector x 1) (my-expression))

      

Don't ask why, I like the regular parentheses better. But Clojure says:

let requires a vector for its binding in ...

      

What's wrong?

+3


source to share


4 answers


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.

+7


source


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.

+3


source


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

      

+3


source


This code, for example, works:

(eval `(let ~(vector 'a 1) (println ~'a)))

      

which means you can write your own let macro that takes a list instead of a vector. This would be nice for your general Clojure experience, and I would not recommend it.

0


source







All Articles