而不是
(let [x 1] (my-expression))
我正在尝试使用:
(let (vector x 1) (my-expression))
不要问为什么,我更喜欢普通的括号。但是Clojure说:
let requires a vector for its binding in ...
怎么了?
答案 0 :(得分:7)
let special form binding form必须是一个向量 literal ,而不仅仅是一个会计算为向量的表达式。
为什么呢?粗略地说,必须先编译表达式,然后才能对其进行求值。在编译时,(vector x 1)
将不会被评估为vector
,它只是一个列表。实际上,如果要对其进行评估,则会评估vector
的参数,这意味着必须解决x
。但是,您不希望解析x
,而是希望它被绑定。
答案 1 :(得分:3)
查看let
宏
(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体验非常不利,我不会建议。