8

我正在学习 Clojure,并试图通过与 Python 的类似功能进行比较来理解 reader、quoting、eval 和 homoiconicity。

在 Python 中,避免(或推迟)评估的一种方法是将表达式括在引号之间,例如。'3 + 4'. 您可以稍后使用 来评估它eval,例如。eval('3 + 4')屈服7。(如果您只需要引用 Python 值,您可以使用repr函数而不是手动添加引号。)

在 Lisp 中,您使用quoteor'来引用和eval评估,例如。(eval '(+ 3 4))屈服7

因此,在 Python 中,“引用”的内容由字符串表示,而在 Lisp 中,它由具有quote第一项的列表表示。

最后,我的问题是:为什么 Clojure 允许(eval 3)虽然3没有被引用?仅仅是 Lisp 风格的问题(尽可能给出答案而不是错误)还是背后有其他原因?这种行为对 Lisp 来说是否必不可少?

4

4 回答 4

6

简短的回答是数字(以及符号和字符串,例如)对自己进行评估。引用指示 lisp(读者)传递未评估的引用后面的任何内容。eval然后在您编写它时获取该列表,但没有引号,然后对其进行评估(在 的情况下(eval '(+ 3 4))eval将评估两个参数的函数调用(+))。

最后一个表达式会发生以下情况:

  1. 当您按 Enter 时,将评估表达式。它包含一个普通的函数调用 ( eval) 和一些参数。
  2. 对参数进行评估。第一个参数包含一个引号,它告诉读者生成引号之后的内容(实际(+ 3 4)列表)。
  3. 没有更多的参数,并评估实际的函数调用。这意味着eval使用列表 (+ 3 4)作为参数调用函数。
  4. eval函数再次执行相同的步骤,找到正常的函数+和参数,并应用它,获得结果。
于 2012-12-27T00:53:06.083 回答
4

其他答案已经解释了机制,但我认为哲学点在于 lisp 和 python 看待“代码”的不同方式。在 python 中,将代码表示为字符串的唯一方法是,因此尝试评估非字符串当然会失败。Lisp 具有更丰富的代码数据结构:列表、数字、符号等。所以表达式(+ 1 2)是一个列表,包含一个符号和两个数字。评估列表时,您必须首先评估其每个元素。

因此,在运行 lisp 代码的普通过程中需要计算一个数字是非常自然的。为此,数字被定义为“对自己进行评估”,这意味着它们在评估后与之前相同:只是一个数字。该函数将相同的规则应用于编译器在编译时将应用eval的裸“代码片段” ,例如,较大表达式的第三个元素,如. 对于数字,这意味着不要管它。3(+ 5 3)

于 2012-12-27T01:58:13.630 回答
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 方言已经定义所有数据类型(除了列表和符号)都是自我评估的。

于 2012-12-27T01:30:48.313 回答
2

要回答这个问题,我们需要查看evallisp 中的定义。例如,在CLHS中有定义:

语法:评估形式 => 结果*

参数和值:形式 - 一种形式。
结果 - 评估形式产生的值。

form在哪里

  1. 任何要评估的对象。
  2. 一个符号、一个复合形式或一个自我评价的对象。
  3. (对于运算符,如<<operator>> form'') a compound form having that operator as its first element.引号形式是常量形式。''

在您的情况下,编号“3”是self-evaluating object. Self-evaluating objecta 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)作为参数。

于 2012-12-27T00:59:18.230 回答