yegor256
yegor256

Reputation: 105203

Why LET doesn't work with VECTOR?

Instead of

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

I'm trying to use:

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

Don't ask why, I just like normal brackets more. But Clojure says:

let requires a vector for its binding in ...

What's wrong?

Upvotes: 3

Views: 526

Answers (4)

Kyle
Kyle

Reputation: 22278

Have a look at the source for the let macro

(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'll notice that the bindings argument is not evaluated when the macro tries to ensure it was given correct arguments via assert-args.

At the point when clojure evaluates (vector? bindings) , bindings is a form (list) containing a fn as the first element followed by it's arguments and therefore is not a vector at that point.

Upvotes: 3

mikera
mikera

Reputation: 106401

let requires a vector for it's bindings (at compile time) so trying to put a vector functional call in its place won't work (as that will only produce a vector at runtime).

However you can make your own let with a bit of macro-fu:

(defmacro mylet [bindings & exprs]
  `(let ~(vec bindings) ~@exprs))

(mylet (x 1) (inc x))
=> 2

Upvotes: 3

Marko Topolnik
Marko Topolnik

Reputation: 200296

This code, for example, does work:

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

which means you could write your own let macro that accepts a list instead of a vector. This would be quite bad for your overall Clojure experience and I wouldn't advise it.

Upvotes: 0

A. Webb
A. Webb

Reputation: 26446

The let special form binding form is required to be a vector literal not just an expression that would evaluate to a vector.

Why? Roughly stated, the expression must be compiled before it can be evaluated. At compile-time (vector x 1) will not have been evaluated to a vector, it will just be a list. Indeed if it were to be evaluated, the arguments of vector would be evaluated, meaning x would have to be resolved. But, you don't want x to be resolved, you want it bound.

Upvotes: 7

Related Questions