14

在我向不熟悉 clojure 的同事解释一些 clojure 代码之前,我从来没有真正想过这个问题。let当他问为什么你使用向量来声明绑定而不是列表时,我正在向他解释。我真的没有给他答案。但是该语言确实限制您使用列表:

=> (let (x 1) x)
java.lang.IllegalArgumentException: let requires a vector for its binding (NO_SOURCE_FILE:0)

为什么会这样?

4

5 回答 5

26

我想主要是可读性。每当在 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
于 2010-10-04T23:57:23.453 回答
13

这是来自 Scheme 的一个成语。在许多 Scheme 实现中,方括号可以与列表文字中的圆括号互换使用。在那些 Scheme 实现中,方括号通常用于将参数列表、参数列表和绑定与 S 表达式或数据列表区分开来。

在 Clojure 中,圆括号和方括号的含义不同,但它们在绑定声明中的使用方式相同。

于 2010-10-05T00:21:22.213 回答
11

Clojure 非常努力地保持一致性。没有技术原因不能在let, fn,with-open等中使用列表表单...事实上,您可以my-let轻松地创建自己的表单,而不是使用列表表单。然而,除了明显突出之外,该向量在表单中始终如一地使用以表示“这里有一些绑定”。您应该努力在自己的代码中维护这一理想。

于 2010-10-04T23:59:10.423 回答
1

我的猜测是这是一个约定

fn用过,defn用过,用过loop

似乎它适用于类似于具有某些参数的代码块的所有内容;更具体地说,方括号用于标记这些参数

其他形式的代码块不要使用它,比如ifor do。他们没有任何参数

于 2010-10-05T06:20:50.093 回答
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))

尽管没有实际理由这样做。

于 2011-05-30T22:24:27.027 回答