3
user=> (eval '(+ 1 2))
3
user=> (eval '('+ 1 2))
2
user=> (eval (list '+ '1 '2))
3
user=> (eval (list + '1 '2))
3

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

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

4

1 回答 1

5

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

(list + '1 '2)生成由符号+和数字命名的函数列表12。评估它将调用已经直接成为列表元素的函数,并使用列表其余部分的参数。

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

编辑

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

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

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

但是,在这种情况下,对 symbol 的调用有第二+个参数,当没有找到匹配的键时,第二个参数被用作返回的默认值。所以这就是表单(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)

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

编辑 3

最后一个添加有望进一步澄清事情:除非它的第一个元素命名宏或特殊运算符,eval否则将递归地评估列表的所有元素(包括第一个),然后通过调用其(评估的)第一个参数作为以列表的其余部分作为参数的函数。

如果第一个元素是'+or (quote +)(这是写同一事物的两种不同方式,带引号的符号+),它将评估为符号+并将其作为函数调用。

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

于 2013-10-01T10:25:18.990 回答