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

And*_*rew 10 lisp interpreter compilation clojure

我想知道Lisp程序的解释/编译过程中"读者"的目的,或者更确切地说是"读者"的任务.

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

'cheese         -->  (quote cheese)
{"a" 1 "b" 2}   -->  (array-map "a" 1 "b" 2)
Run Code Online (Sandbox Code Playgroud)

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

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

谢谢!

Rai*_*wig 20

通常,Lisp中的读取器读取s表达式并返回数据结构.READ是I/O操作:输入是字符流,输出是Lisp数据.

打印机则正好相反:它需要Lisp的数据,并输出作为那些字符流.因此,它也可以将Lisp数据打印到外部s表达式.

请注意,解释意味着特定的东西:由解释器执行代码.但是许多Lisp系统(包括Clojure)都在使用编译器.计算Lisp表单值的任务通常称为评估.评估可以通过解释,汇编或两者的混合来实现.

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
Run Code Online (Sandbox Code Playgroud)

Lisp的语法通常是在Lisp数据之上定义的.

IF具有以下语法(在Common Lisp中http://www.lispworks.com/documentation/HyperSpec/Body/s_if.htm):

if test-form then-form [else-form]
Run Code Online (Sandbox Code Playgroud)

所以它需要一个测试形式,一个then-form和一个可选的else-form.

作为s表达式,以下是有效的IF表达式:

(if (foo) 1 2)
(if (bar) (foo))
Run Code Online (Sandbox Code Playgroud)

但是由于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
Run Code Online (Sandbox Code Playgroud)

例如,可以使用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
Run Code Online (Sandbox Code Playgroud)

所以最原始的REPL是:

(loop (print (eval (read))))
Run Code Online (Sandbox Code Playgroud)

因此,从概念的角度来看,为了回答你的问题,在评估期间,读者什么都不做.它不参与评估.评估由EVAL功能完成.通过调用READ调用读者.由于EVAL使用Lisp数据结构作为输入(而不是s表达式),因此读取器在Lisp表单被评估之前运行(例如通过解释或通过编译和执行它).

  • @Andrew:对.通常,读者不会评估事物.它只是为s-expression创建一个Lisp数据结构.现在,评估者可以解释这些内部数据结构 - 词法分析器阶段已经完成.通常,这些程序作为数据在中间步骤中被编译为机器或字节代码.另请注意,例如Common Lisp reader具有评估内容的功能.'(1 2#.(+ 1 2))返回(1 2 3).#.是一个读取器宏,在读取时评估下一个表达式.还可以通过读表实现其他行为. (4认同)
  • 谢谢你的澄清.因此,有人可能会说,读者将程序数据读入为纯文本结构为S表达式,并返回一个Lisp数据结构.它不评估任何这些表达式,而只是以一种可以有效评估的方式在内存中表示它们?我现在更清楚地看到评估者之间的区别(根据SICP的"metacircular abstraction"章节,其中提供了一个简单的lisp-in-lisp评估器)和一个完全成熟的解释器. (3认同)