我想知道Lisp程序的解释/编译过程中“读者”的目的,或者更确切地说是这个目的。
从我刚刚完成的前期问题研究中,在我看来,读者(在这种情况下特别是Clojure)可以被认为是“语法预处理器”。它的主要职责是读者宏和原始形式的扩展。那么,有两个例子:
'cheese --> (quote cheese)
{"a" 1 "b" 2} --> (array-map "a" 1 "b" 2)
所以读者接受一个程序的文本(由S-Expressions组成),然后构建并返回一个可以直接评估的内存数据结构。
这与事实有多远(我是否过度简化了整个过程)?读者还有哪些其他任务?考虑到Lisps的优点是它们的同质性(代码作为数据),为什么需要进行词法分析(如果这确实与读者的工作相当)?
谢谢!
答案 0 :(得分:20)
通常,Lisp中的读取器读取s表达式并返回数据结构。 READ是一个I / O操作:输入是一个字符流,输出是Lisp数据。
打印机正好相反:它接受Lisp数据并将其作为字符流输出。因此,它也可以将Lisp数据打印到外部s表达式。
请注意,解释意味着特定的东西:由口译员执行代码。但是许多Lisp系统(包括Clojure)都在使用编译器。计算Lisp表单值的任务通常称为 evaluation 。评估可以通过解释,汇编或两者的混合来实现。
S-Expression :符号表达式。外部的,文本的数据表示。外部意味着s表达式是您在文本文件,字符串等中看到的。因此,s表达式由某些(通常是外部的)中的字符组成。
Lisp数据结构:符号,列表,字符串,数字,字符......
Reader :读取s表达式并返回Lisp数据结构。
请注意,s表达式也用于编码Lisp源代码。
在一些Lisp方言中,阅读器是可编程的和表驱动的(通过所谓的读表)。该读表包含字符的读取器功能。例如,引号'字符绑定到一个函数,该函数读取表达式并返回(list'szotes表达式)的值。数字字符0..9绑定到读取数字的函数(实际上这可能更复杂,因为一些Lisps允许数字以不同的基数读取)。
S表达式为数据结构提供外部语法。
Lisp程序使用s表达式以外部形式编写。但并非所有的s表达式都是有效的Lisp程序:
(if a b c d e) is usually not a valid Lisp program
Lisp的语法通常是在Lisp数据之上定义的。
IF具有以下语法(在Common Lisp http://www.lispworks.com/documentation/HyperSpec/Body/s_if.htm中):
if test-form then-form [else-form]
所以它需要一个测试形式,一个then-form和一个可选的else-form。
作为s表达式,以下是有效的IF表达式:
(if (foo) 1 2)
(if (bar) (foo))
但是由于Lisp程序是表单,我们也可以使用Lisp程序构建这些表单:
(list'if'(foo)1 2)是一个返回有效IF表单的Lisp程序。
CL-USER 24 > (describe (list 'if '(foo) 1 2))
(IF (FOO) 1 2) is a LIST
0 IF
1 (FOO)
2 1
3 2
此列表可以例如使用EVAL执行。 EVAL需要列表形式 - 而不是s表达式。记住s表达式只是一个外部表示。要创建一个Lisp表单,我们需要阅读它。
这就是为什么说代码是数据。 Lisp表单表示为内部Lisp数据结构:列表,符号,数字,字符串......在大多数其他编程语言中,代码是原始文本。在Lisp中,s表达式是原始文本。当使用READ函数读取时,s表达式将转换为数据。
因此,Lisp中的基本交互顶层称为REPL,Read Eval Print Loop。 它是一个重复读取s表达式的LOOP,评估lisp表单并打印它:
READ : s-expression -> lisp data
EVAL : lisp form -> resulting lisp data
PRINT: lisp data -> s-expression
所以最原始的REPL是:
(loop (print (eval (read))))
因此,从概念的角度来看,回答你的问题,在评估期间,读者什么都不做。它不参与评估。评估由EVAL功能完成。通过调用READ调用读者。由于EVAL使用Lisp数据结构作为输入(而不是s表达式),因此读者在Lisp表单被评估之前运行(例如通过解释或通过编译和执行它)。