Lisp解释过程中“读者”的任务是什么?

时间:2010-12-27 09:43:17

标签: clojure lisp compilation interpreter

我想知道Lisp程序的解释/编译过程中“读者”的目的,或者更确切地说是这个目的。

从我刚刚完成的前期问题研究中,在我看来,读者(在这种情况下特别是Clojure)可以被认为是“语法预处理器”。它的主要职责是读者宏和原始形式的扩展。那么,有两个例子:

'cheese         -->  (quote cheese)
{"a" 1 "b" 2}   -->  (array-map "a" 1 "b" 2)

所以读者接受一个程序的文本(由S-Expressions组成),然后构建并返回一个可以直接评估的内存数据结构。

这与事实有多远(我是否过度简化了整个过程)?读者还有哪些其他任务?考虑到Lisps的优点是它们的同质性(代码作为数据),为什么需要进行词法分析(如果这确实与读者的工作相当)?

谢谢!

1 个答案:

答案 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表单被评估之前运行(例如通过解释或通过编译和执行它)。