为什么在clojure(eval(list + 1 2))和(eval(list'+ 1 2))做同样的事情?

sno*_*now 3 clojure quote

user=> (eval '(+ 1 2))
3
user=> (eval '('+ 1 2))
2
user=> (eval (list '+ '1 '2))
3
user=> (eval (list + '1 '2))
3
Run Code Online (Sandbox Code Playgroud)

这是否意味着'+有时与+相同?

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

Rör*_*örd 5

(list '+ '1 '2)产生符号列表+和编号12.评估它将查找符号命名的函数+并使用参数1和调用它2.

(list + '1 '2)生产用符号命名的函数列表+以及数字12.评估它将使用列表其余部分的参数调用已经直接作为列表元素的函数.

顺便说一下,从来没有必要引用数字.他们是自我评价的.

编辑:

你在标题中没有提到的更有趣的案例是(eval '('+ 1 2))案件中会发生什么?为什么会出现这种不返回3像其他情况下,所有最终调用由指定的功能+与参数12

答案是它有所不同,因为这一次,你引用了+两次符号.因此,符号不会被解析为它命名的函数,而是将符号本身称为函数.

现在当符号作为函数被调用时的行为是什么?它将其第一个参数视为地图,并将自己视为该地图中的关键.但这个数字1显然不是一张地图,所以现在通常会返回nil以表示没有找到匹配的密钥.

但是在这种情况下,对符号的调用有第二个参数+,第二个参数被用作默认值,当没有找到匹配的键时返回.这就是表单(eval '('+ 1 2))返回的原因2.

编辑2:

好的,现在最后回答这个问题:为什么引用列表会产生与调用list具有相同参数的函数不同的结果.这是因为引用会'停止对其使用的列表进行所有评估,但该list函数会在生成包含它们作为元素的列表之前评估其参数.

当您打印各种表单而不是直接发送到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)
Run Code Online (Sandbox Code Playgroud)

您会看到第一个和第三个案例产生的结果相同,因为在这两种情况下您都引用了+一次.在第二种情况下,+引用两次,而在最后一次它根本没有引用.

编辑3:

最后一个补充应该有希望进一步澄清:除非它的第一个元素命名为宏或特殊运算符,eval否则在通过调用其(已计算的)第一个参数作为a来评估列表本身之前递归计算列表的所有元素(包括第一个元素).以列表的其余部分作为参数运行.

如果第一个元素是'+(quote +)(这是两种不同的方式来编写相同的东西,引用的符号+),它将评估为符号+,并将被称为函数.

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