在我向不熟悉clojure的同事解释一些clojure代码之前,我从未真正考虑过这个问题。当他问你为什么使用向量来声明绑定而不是列表时,我向他解释let
。我对他没有真正的答案。但语言确实限制您使用列表:
=> (let (x 1) x)
java.lang.IllegalArgumentException: let requires a vector for its binding (NO_SOURCE_FILE:0)
为什么会这样?
答案 0 :(得分:25)
我想象的大部分是可读性。无论何时在Clojure中需要绑定,都会使用矢量。很多人都认为绑定的向量可以使事情更好地流动,并且更容易识别绑定是什么以及正在运行的代码是什么。
只是为了好玩:
user=> (defmacro list-let [bindings & body] `(let ~(vec bindings) ~@body))
#'user/list-let
user=> (macroexpand-1 '(list-let (x 0) (println x)))
(clojure.core/let [x 0] (println x))
user=> (list-let (x 0 y 1) (println x y))
0 1
nil
答案 1 :(得分:13)
这是Scheme的成语。在许多Scheme实现中,方括号可以与列表文字中的圆括号互换使用。在那些Scheme实现中,方括号通常用于区分参数列表,参数列表和S表达式或数据列表中的绑定。
在Clojure中,括号和括号表示不同的内容,但它们在绑定声明时的使用方式相同。
答案 2 :(得分:11)
Clojure非常努力地保持一致。没有技术原因,列表表单无法在let
,fn
,with-open
等中使用...事实上,您可以创建自己的my-let
很容易使用一个而不是。然而,除了明显突出外,矢量在形式上一致地使用意味着“这里有一些约束”。你应该努力在你自己的代码中坚持这个理想。
答案 3 :(得分:1)
我的猜测是一个约定
fn
使用了它,defn
使用了它,loop
使用了它。
它似乎适用于所有类似于具有某些参数的代码块的内容;更具体地说,方括号用于标记那些参数
代码块的其他形式不使用它,例如if
或do
。他们没有任何参数
答案 4 :(得分:1)
另一种思考方式是let
只是从lambda派生而来。这两个表达式是等价的:
((fn [y] (+ y 42)) 10)
(let [y 10] (+ 42 y))
因此,作为学术或教学点,您甚至可以编写自己的let
非常基本的版本,其中包含列表和矢量:
(defmacro my-let [x body]
(list (list `fn[(first x)]
`~body)
(last x)))
(my-let (z 42) (* z z))
虽然没有实际的理由这样做。