我正在学习Clojure并尝试通过与Python的类似功能相似来理解读者,引用,评估和同质性。
在Python中,避免(或推迟)评估的一种方法是将表达式包装在引号之间,例如。 '3 + 4'
。您可以稍后使用eval
对此进行评估,例如。 eval('3 + 4')
屈服7
。 (如果只需要引用Python值,可以使用repr
函数而不是手动添加引号。)
在Lisp中,您使用quote
或'
进行引用,使用eval
进行评估,例如。 (eval '(+ 3 4))
屈服于7
。
因此在Python中,“引用”的东西由字符串表示,而在Lisp中,它由以quote
作为第一项的列表表示。
我的问题,最后:为什么Clojure允许(eval 3)
虽然没有引用3
?这只是Lisp风格的问题(试图尽可能给出答案而不是错误)或者还有其他原因吗?这种行为对Lisp是否必不可少?
答案 0 :(得分:6)
简短的回答是数字(以及符号和字符串)对自己进行评估。引用指示lisp(读者)在报价后面传递未评估的内容。 eval
然后在编写时获取该列表,但没有引号,然后对其进行评估(在(eval '(+ 3 4))
的情况下,eval
将评估函数调用(+
)超过两个论点)。
最后一个表达式会发生以下情况:
eval
)和一些参数。(+ 3 4)
列表)。eval
作为参数调用(+ 3 4)
函数。eval
函数再次执行相同的步骤,找到正常函数+
和参数,并应用它,获得结果。答案 1 :(得分:4)
其他答案已经解释了这些机制,但我认为哲学观点在于lisp和python以不同的方式看待"代码"。在python中,表示代码的唯一方法是作为字符串,因此当然尝试评估非字符串将失败。 Lisp为代码提供了更丰富的数据结构:列表,数字,符号等。所以表达式(+ 1 2)
是一个列表,包含一个符号和两个数字。评估列表时,必须首先评估每个元素。
因此,在运行lisp代码的普通过程中需要评估一个数字是很自然的。为此,数字被定义为"评估自己",意味着它们在评估之后与之前相同:只是一个数字。 eval
函数将相同的规则应用于裸#34;代码段"编译器在编译时会应用3
,例如,像(+ 5 3)
这样的较大表达式的第三个元素。对于数字,这意味着不管它。
答案 2 :(得分:3)
3
应该评估什么? Lisp最有意义的是评估一个数字。我们是否要求在代码中引用数字?这不是非常方便而且极其成问题:
而不是
(defun add-fourtytwo (n)
(+ n 42))
我们必须写
(defun add-fourtytwo (n)
(+ n '42))
代码中的每个数字都需要引用。缺少引用会触发错误。这不是人们想要使用的东西。
作为旁注,想象一下当您想在代码中使用eval
时会发生什么。
(defun example ()
(eval 3))
以上是错的。需要引用数字。
(defun example ()
(eval '3))
上面没问题,但在运行时会产生错误。 Lisp将'3
评估为数字3.但是然后在数字上调用eval
将是一个错误,因为它们需要被引用。
所以我们需要写:
(defun example ()
(eval ''3))
这不是很有用......
在Lisp历史中,数字总是自我评估。但在早期的Lisp实现中,一些其他数据对象(如数组)不能自我评估。同样,由于这是一个巨大的错误来源,像Common Lisp这样的Lisp方言已经定义了所有数据类型(列表和符号除外)都是自我评估的。
答案 3 :(得分:2)
要回答这个问题,我们需要查看lisp中的eval
定义。例如。在CLHS中有定义:
语法:eval form =>结果*
参数和价值观: 形式 - 形式 结果 - 表格评估产生的价值。
form
- 任何要评估的对象。
- 符号,复合形式或自我评估对象。
- (对于运营商,如
醇><<operator>> form'') a compound form having that operator as its first element.
报价单中的表格 常数形式。''
在您的情况下,数字“3”为self-evaluating object
。 Self-evaluating object
是a form that is neither a symbol nor a cons is defined to be a self-evaluating object
。我相信对于clojure,我们可以在此定义中将cons
替换为list
。
在clojure中,lists
只将eval
解释为函数调用。其他数据结构和对象被评估为自我评估对象。
'(+ 3 4)
等于(list '+ 3 4)
。 '
(由读者转换为quote
函数)只是避免评估给定的形式。因此,在表达式(eval '(+ 3 4))
eval
中,将列表数据结构('+ 3 4)
作为参数。