clojure - Lisp解释时 "reader"的任务是什么?

标签 clojure lisp compilation interpreter

我想知道“读者”在解释/编译 Lisp 程序期间的目的,或者更准确地说,他们的任务。

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

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

因此,读者接收程序文本(由 S 表达式组成),然后构建并返回一个可以直接计算的内存数据结构。

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

谢谢!

最佳答案

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

打印机 做相反的事情:它获取 Lisp 数据并将其输出为字符流。因此它也可以将 Lisp 数据打印到外部 s 表达式。

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

S-Expression:符号表达式。数据的外部文本表示。外部意味着 s-expressions 是您在文本文件、字符串等中看到的内容。因此 s-expressions 由某些(通常是外部)介质上的字符组成。

Lisp 数据结构:符号、列表、字符串、数字、字符……

Reader:读取 s 表达式并返回 Lisp 数据结构。

请注意,s 表达式也用于对 Lisp 源代码进行编码。

在某些 Lisp 方言中,读取器是可编程的并且是表驱动的(通过所谓的读取表)。此读取表包含字符的读取器函数。例如,quote ' 字符绑定(bind)到一个函数,该函数读取表达式并返回 (list 'quote expression) 的值。数字字符 0..9 绑定(bind)到读取数字的函数(实际上这可能更复杂,因为某些 Lisp 允许以不同的基数读取数字)。

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 表单和一个可选的 else 表单。

作为 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-expressions 被转换为数据。

因此,Lisp 中的基本交互顶层称为 REPL,Read Eval Print Loop。 这是一个重复读取 s 表达式、评估 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 形式被评估之前运行(例如通过解释或通过编译和执行它)。

关于clojure - Lisp解释时 "reader"的任务是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4537793/

相关文章:

clojure 用它的答案替换运算符

clojure - 运行时常量的 var 与atom

memory-management - 何时在 lisp 解释器中释放闭包的内存

python - 如何识别数学运算符

c - 针对 glib 进行编译时出现链接器错误...?

clojure - 宏内调用函数和宏的区别?

java - Clojure,Java interop : how to get File. 分隔符?

emacs - 如何将参数传递给 emacs lisp 中的映射?

scheme - 使用 eval、R5RS 从列表中评估我自己的函数

c# - C#编译器的泛型、继承和失败的方法解析