为什么在clojure中(eval(list+;12))和(eval(list';+;12))做同样的事情?

为什么在clojure中(eval(list+;12))和(eval(list';+;12))做同样的事情?,clojure,quote,Clojure,Quote,这是否意味着“+有时与+”相同 是否有任何规则来确定应考虑的情况?(列表'+'1'2)生成符号+和数字1和2的列表。计算它将查找由符号+命名的函数,并使用参数1和2调用它 (list+'1'2)生成一个函数列表,该函数由符号+和数字1和2命名。对其求值将调用已直接作为列表元素的函数,该函数包含列表其余部分的参数 顺便说一句,根本不需要引用数字。他们在自我评估 编辑: 你没有在标题中提到的更有趣的案例是(eval'('+12))案例中发生了什么?为什么它不返回3,就像其他情况一样,所有这些情况最终

这是否意味着“+有时与+”相同

是否有任何规则来确定应考虑的情况?

(列表'+'1'2)
生成符号
+
和数字
1
2
的列表。计算它将查找由符号
+
命名的函数,并使用参数
1
2
调用它

(list+'1'2)
生成一个函数列表,该函数由符号
+
和数字
1
2
命名。对其求值将调用已直接作为列表元素的函数,该函数包含列表其余部分的参数

顺便说一句,根本不需要引用数字。他们在自我评估

编辑

你没有在标题中提到的更有趣的案例是
(eval'('+12))
案例中发生了什么?为什么它不返回
3
,就像其他情况一样,所有这些情况最终都使用参数
1
2
调用了名为
+
的函数

答案是它不同,因为这一次,您引用了符号
+
两次。因此,符号不会解析为它命名的函数,而是将符号本身作为函数调用

现在,当一个符号作为函数被调用时,它的行为是什么?它将其第一个参数视为一个映射,并将自己作为该映射中的一个键进行查找。但是数字
1
显然不是映射,因此它现在通常返回
nil
,以指示未找到匹配的键

不过,在本例中,对符号
+
的调用还有第二个参数,当找不到匹配键时,第二个参数将用作返回的默认值。这就是为什么表单
(eval'('+12))
返回
2

编辑2

好,现在最后回答这个问题:为什么引用列表会产生不同的结果,而不是使用相同的参数调用
list
函数。这是因为引号
会停止对其使用的列表的所有求值,但是
list
函数会在生成一个将其参数作为元素的列表之前对其参数求值

当您打印各种表格而不是直接将其发送到
eval
时,这些差异都变得非常明显:

user=> (eval '(+ 1 2))
3
user=> (eval '('+ 1 2))
2
user=> (eval (list '+ '1 '2))
3
user=> (eval (list + '1 '2))
3
user>”(+12)
(+ 1 2)
用户>'('+1 2)
((引文+)1 2)
用户>(列表“+”1“2)
(+ 1 2)
用户>(列表+1'2)
(# 1 2)
您可以看到,第一种和第三种情况产生的结果是相同的,因为在这两种情况下,您都引用了
+
一次。在第二种情况下,
+
被引用了两次,而在最后一种情况下,它根本没有被引用

编辑3

最后一个补充,有望进一步澄清问题:除非它的第一个元素命名为宏或特殊运算符,
eval
将递归地计算列表中的所有元素(包括第一个元素),然后通过调用它的(evaluated)来计算列表本身第一个参数作为函数,列表的其余部分作为参数

如果第一个元素是
'+
(quote+)
(这是两种不同的方法来编写相同的东西,引用的符号
+
),它将计算为符号
+
,并将其作为函数调用

如果第一个元素是
+
,那么它将计算为实际的加法函数(
clojure.core$\u PLUS
)。如果它已经是该函数,它将保持不变(基本上除了列表和符号之外的所有类型都是自评估的)。在这两种情况下,
eval
将调用该函数

user> '(+ 1 2)
(+ 1 2)
user> '('+ 1 2)
((quote +) 1 2)
user> (list '+ '1 '2)
(+ 1 2)
user> (list + '1 '2)
(#<core$_PLUS_ clojure.core$_PLUS_@165c64> 1 2)