为啥 let 需要一个向量?
Posted
技术标签:
【中文标题】为啥 let 需要一个向量?【英文标题】:Why does let require a vector?为什么 let 需要一个向量? 【发布时间】:2011-04-21 01:26:49 【问题描述】:在我向不熟悉 clojure 的同事解释一些 clojure 代码之前,我从来没有真正想过这个问题。当他问为什么你使用向量来声明绑定而不是列表时,我正在向他解释let
。我真的没有给他答案。但是语言确实限制您使用列表:
=> (let (x 1) x)
java.lang.IllegalArgumentException: let requires a vector for its binding (NO_SOURCE_FILE:0)
为什么会这样?
【问题讨论】:
我想这纯粹是为了可读性,而 let 强制执行向量只是确保保留成语。 (几乎所有“let”和“with-”宏都需要文字向量。) 这有点像自然法则。你可以推理那个它是那样的,但不能为什么。这个决定的真正原因是否是可读性、某些方案的实施、惯例或 Rich 那天吃的早餐类型仍然是未知数。能回答这个问题的,只有里奇本人。对于 Clojure,我们处于一个幸运的位置,对于宇宙来说...... 【参考方案1】:我想主要是可读性。每当在 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
【讨论】:
我投票支持这个答案,因为它比我的答案快 2 分钟 并且 有代码!好节目! 没错,Hickey 在他的...并发演讲中提到了可读性原因,我认为是。 使用文字向量也清楚地表明它不是函数调用。 list-let 有效,但您必须知道第一个列表未正常评估。一旦你掌握了文字向量语法,你不妨利用它。 我倾向于在需要时在宏中写 [~@bindings] 而不是 ~(vec binding)。我发现它更容易阅读。 Hamish:他的并发演讲? Rich 上一次谈论不涉及并发的事情是什么时候? :-)【参考方案2】:这是一个来自 Scheme 的成语。在许多 Scheme 实现中,方括号可以与列表文字中的圆括号互换使用。在那些 Scheme 实现中,方括号通常用于将参数列表、参数列表和绑定与 S 表达式或数据列表区分开来。
在 Clojure 中,圆括号和方括号的含义不同,但它们在绑定声明中的使用方式相同。
【讨论】:
【参考方案3】:Clojure 非常努力地保持一致性。没有技术原因不能在let
、fn
、with-open
等中使用列表表单。事实上,您可以很容易地创建自己的my-let
来代替使用一个。然而,除了明显突出之外,该向量在表单中始终如一地使用以表示“这里有一些绑定”。您应该努力在自己的代码中维护这一理想。
【讨论】:
【参考方案4】:我猜这是约定
fn
用过,defn
用过,loop
用过。
似乎它适用于所有类似于具有某些参数的代码块的东西;更具体地说,方括号用于标记这些参数
其他形式的代码块不要使用它,例如if
或do
。他们没有任何参数
【讨论】:
【参考方案5】:另一种思考方式是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))
虽然没有实际理由这样做。
【讨论】:
以上是关于为啥 let 需要一个向量?的主要内容,如果未能解决你的问题,请参考以下文章