lisp 如何决定是评估列表还是将其用作数据?
How does lisp decide whether to evaluate a list or use it as data?
如果你写类似 (+ 2 3)
的东西,+
将被视为一个函数,如果 +
没有任何与之关联的函数定义,则会发生错误。
如果您写类似 (let (a b c))
的内容,(a b c)
将被读取为数据。
lisp 是如何决定的?
这里有两个基本的 lisp 概念需要理解:
- 阅读与评价的区别
- 特殊形式
- 符号
阅读诉评估
阅读是将文本转换为lisp对象的行为。数字和列表等 Lisp 对象具有所谓的 阅读形式 ,这是一种可以读入对象的文本表示。它通常与打印表格相同。如果您来自 Java 等语言,toString() 给出对象的打印形式。阅读没有等价的概念,因为Lisp有有趣和强大的属性,Lisp源代码是一个lisp对象
需要注意的是,阅读不等于评价,虽然很多对象都是自我评价的。例如,一个数字是一个对象,在计算时,return 就是它本身。更常见的说法是许多 表格 自我评估,但您应该记住,上下文中的 "form" 通常与 "lisp object," 同义,暗示将评估对象。
考虑一下当我们在 REPL 中 运行 一个简单的程序时会发生什么可能会很有用。回想一下 "REPL" 代表 "Read, evaluate, print, loop",而 Lisp 是这些步骤之间的区别非常明显的语言。
考虑列表程序:
161
当你在 REPL 中 运行 时,结果如下:
161
这里发生的事情如下:
- 读: 读形式 "161" 转换为Lisp中的数字161的对象
- 评价:数字161为自评表。所以 161 的计算结果为 161.
- 打印:数字161的打印表示是“161”。所以这个数字被打印出来了。
- 循环: 再次提示输入。
符号:不自评表
符号的阅读形式将是文本,如 abc
。符号计算它们持有的变量。让我们 运行 REPL 中的程序 abc
:
abc
这个程序实际上产生了错误:
eval-last-sexp-1: Symbol's value as variable is void: abc
这里发生的是:
- 读取了 s 表达式 "abc"
- 它是符号 abc 的读取形式,因此创建了该对象。
- 符号 abc 对其变量求值,但是,它当前没有变量(使用 "void"),因此它出错
特殊形式setq
会将符号设置为指向一个变量。更多内容见下文。
特殊形式
从这里开始,Lisp 与大多数语言一样工作。调用 (+ 1 (+ 2 3))
将执行与 plus(1, plus(2,3))
相同的操作,在具有加号功能的命令式语言中。整个表达式将是红色的,以构建列表对象 (+ 1 (+ 2 3 ))
,这是一个包含三个元素的列表 +
、1
和列表 (+2 3)
。然后,作为函数调用的外部 +
将导致解释器评估对象 1
,它是自评估的,而 (+ 2 3)
最终将评估为 5。然后+
将获取两个评估对象,1
和 5
,并将它们相加,并且 return 6
.
但是,Lisp 有所谓的特殊形式。特殊形式 可以跳过计算步骤 并只使用原始对象。例如,setq
是一种计算第二个参数而不是第一个参数的特殊形式。
(setq a (+ 2 3))
将不计算符号"a",但会将符号"a"赋值给(+ 2 3)
计算的对象,即,数字 5。然后,调用
a
在 REPL 中将打印 5
.
所以要回答最初的问题..."let" 是一种特殊形式,因此不会立即评估其参数:)
宏
宏也不评估它们的论点,但对于原始问题可能没有必要进行全面讨论。
If you write something like (let (a b c)), (a b c) is read as data.
不是真的。一切都是一样的。首先阅读 Lisp 形式。完全。评估稍后进行。评估有所作为。
一个LET
表达式是一种特殊的形式,该形式根据特殊的规则求值。
参见 Emacs Lisp 手册:Parts of let Expression。
Lisp 有
- 函数调用如
(* a b)
- 特殊形式,如
(let ((a 1)) a)
。这些表单通常是内置的,不能由用户扩展。
- 宏形式喜欢
(defun foo () nil)
- 加上 Lisp 方言提供的任何其他内容...
标识符,即列表中的第一个元素,告诉我们如何评估表单。
如果你写类似 (+ 2 3)
的东西,+
将被视为一个函数,如果 +
没有任何与之关联的函数定义,则会发生错误。
如果您写类似 (let (a b c))
的内容,(a b c)
将被读取为数据。
lisp 是如何决定的?
这里有两个基本的 lisp 概念需要理解:
- 阅读与评价的区别
- 特殊形式
- 符号
阅读诉评估
阅读是将文本转换为lisp对象的行为。数字和列表等 Lisp 对象具有所谓的 阅读形式 ,这是一种可以读入对象的文本表示。它通常与打印表格相同。如果您来自 Java 等语言,toString() 给出对象的打印形式。阅读没有等价的概念,因为Lisp有有趣和强大的属性,Lisp源代码是一个lisp对象
需要注意的是,阅读不等于评价,虽然很多对象都是自我评价的。例如,一个数字是一个对象,在计算时,return 就是它本身。更常见的说法是许多 表格 自我评估,但您应该记住,上下文中的 "form" 通常与 "lisp object," 同义,暗示将评估对象。
考虑一下当我们在 REPL 中 运行 一个简单的程序时会发生什么可能会很有用。回想一下 "REPL" 代表 "Read, evaluate, print, loop",而 Lisp 是这些步骤之间的区别非常明显的语言。
考虑列表程序:
161
当你在 REPL 中 运行 时,结果如下:
161
这里发生的事情如下:
- 读: 读形式 "161" 转换为Lisp中的数字161的对象
- 评价:数字161为自评表。所以 161 的计算结果为 161.
- 打印:数字161的打印表示是“161”。所以这个数字被打印出来了。
- 循环: 再次提示输入。
符号:不自评表
符号的阅读形式将是文本,如 abc
。符号计算它们持有的变量。让我们 运行 REPL 中的程序 abc
:
abc
这个程序实际上产生了错误:
eval-last-sexp-1: Symbol's value as variable is void: abc
这里发生的是:
- 读取了 s 表达式 "abc"
- 它是符号 abc 的读取形式,因此创建了该对象。
- 符号 abc 对其变量求值,但是,它当前没有变量(使用 "void"),因此它出错
特殊形式setq
会将符号设置为指向一个变量。更多内容见下文。
特殊形式
从这里开始,Lisp 与大多数语言一样工作。调用 (+ 1 (+ 2 3))
将执行与 plus(1, plus(2,3))
相同的操作,在具有加号功能的命令式语言中。整个表达式将是红色的,以构建列表对象 (+ 1 (+ 2 3 ))
,这是一个包含三个元素的列表 +
、1
和列表 (+2 3)
。然后,作为函数调用的外部 +
将导致解释器评估对象 1
,它是自评估的,而 (+ 2 3)
最终将评估为 5。然后+
将获取两个评估对象,1
和 5
,并将它们相加,并且 return 6
.
但是,Lisp 有所谓的特殊形式。特殊形式 可以跳过计算步骤 并只使用原始对象。例如,setq
是一种计算第二个参数而不是第一个参数的特殊形式。
(setq a (+ 2 3))
将不计算符号"a",但会将符号"a"赋值给(+ 2 3)
计算的对象,即,数字 5。然后,调用
a
在 REPL 中将打印 5
.
所以要回答最初的问题..."let" 是一种特殊形式,因此不会立即评估其参数:)
宏
宏也不评估它们的论点,但对于原始问题可能没有必要进行全面讨论。
If you write something like (let (a b c)), (a b c) is read as data.
不是真的。一切都是一样的。首先阅读 Lisp 形式。完全。评估稍后进行。评估有所作为。
一个LET
表达式是一种特殊的形式,该形式根据特殊的规则求值。
参见 Emacs Lisp 手册:Parts of let Expression。
Lisp 有
- 函数调用如
(* a b)
- 特殊形式,如
(let ((a 1)) a)
。这些表单通常是内置的,不能由用户扩展。 - 宏形式喜欢
(defun foo () nil)
- 加上 Lisp 方言提供的任何其他内容...
标识符,即列表中的第一个元素,告诉我们如何评估表单。