为什么LET不适用于VECTOR?

时间:2013-02-19 21:26:41

标签: clojure

而不是

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

我正在尝试使用:

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

不要问为什么,我更喜欢普通的括号。但是Clojure说:

let requires a vector for its binding in ...

怎么了?

4 个答案:

答案 0 :(得分:7)

let special form binding form必须是一个向量 literal ,而不仅仅是一个会计算为向量的表达式。

为什么呢?粗略地说,必须先编译表达式,然后才能对其进行求值。在编译时,(vector x 1)将不会被评估为vector,它只是一个列表。实际上,如果要对其进行评估,则会评估vector的参数,这意味着必须解决x。但是,您不希望解析x,而是希望它被绑定。

答案 1 :(得分:3)

查看let

source
(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))

当宏尝试通过bindings确保给出正确的参数时,您会注意到assert-args参数未被评估。

当clojure评估(vector? bindings)时,bindings是一个表单(list),其中包含fn作为第一个元素,后跟它的参数和因此,此时不是vector

答案 2 :(得分:3)

let需要一个用于绑定的向量(在编译时),因此尝试将向量函数调用放在其位置将不起作用(因为这只会在运行时生成向量)。

但是你可以用一些宏观的东西来自己动手:

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

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

答案 3 :(得分:0)

例如,此代码可以正常工作:

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

这意味着您可以编写自己的let宏来接受列表而不是向量。这对你的整体Clojure体验非常不利,我不会建议。