在我向一个不熟悉clojure的同事解释一些clojure代码之前,我从未真正想过这个 . 当他问你为什么使用向量来声明绑定而不是列表时,我向他解释了 let . 我真的没有他的答案 . 但该语言确实限制您使用列表:
let
=> (let (x 1) x) java.lang.IllegalArgumentException: let requires a vector for its binding (NO_SOURCE_FILE:0)
这究竟是为什么?
考虑这一点的另一种方法是 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))
虽然没有实际的理由这样做 .
我想,大部分是可读性 . 每当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
Clojure非常努力地保持一致 . 没有技术原因,列表表单无法在 let , fn , with-open 等中使用...事实上,您可以轻松创建自己的 my-let ,而不是使用一个 . 然而,除了明显突出外,矢量在形式上一致地使用意味着"here are some bindings" . 你应该努力在你自己的代码中坚持这个理想 .
fn
with-open
my-let
我的猜测是这是一个惯例
fn 使用它, defn 使用它, loop 使用 .
defn
loop
它似乎适用于所有类似于具有一些参数的代码块的东西;更具体地说,方括号用于标记这些参数
代码块的其他形式不使用它,如 if 或 do . 他们没有任何参数
if
do
这是Scheme的成语 . 在许多Scheme实现中,方括号可以与列表文字中的圆括号互换使用 . 在那些Scheme实现中,方括号通常用于区分参数列表,参数列表和S表达式或数据列表中的绑定 .
在Clojure中,括号和括号表示不同的内容,但它们在绑定声明时的使用方式相同 .
5 回答
考虑这一点的另一种方法是
let
简单地来自lambda . 这两个表达式是等价的:因此,作为一个学术或教学点,您甚至可以编写自己的非常基本的
let
版本,其中列出了一个列表以及一个向量:虽然没有实际的理由这样做 .
我想,大部分是可读性 . 每当Clojure中需要绑定时,就会始终使用向量 . 很多人都认为绑定的向量可以使事情更好地流动,并且更容易识别绑定是什么以及正在运行的代码是什么 .
纯娱乐:
Clojure非常努力地保持一致 . 没有技术原因,列表表单无法在
let
,fn
,with-open
等中使用...事实上,您可以轻松创建自己的my-let
,而不是使用一个 . 然而,除了明显突出外,矢量在形式上一致地使用意味着"here are some bindings" . 你应该努力在你自己的代码中坚持这个理想 .我的猜测是这是一个惯例
fn
使用它,defn
使用它,loop
使用 .它似乎适用于所有类似于具有一些参数的代码块的东西;更具体地说,方括号用于标记这些参数
代码块的其他形式不使用它,如
if
或do
. 他们没有任何参数这是Scheme的成语 . 在许多Scheme实现中,方括号可以与列表文字中的圆括号互换使用 . 在那些Scheme实现中,方括号通常用于区分参数列表,参数列表和S表达式或数据列表中的绑定 .
在Clojure中,括号和括号表示不同的内容,但它们在绑定声明时的使用方式相同 .