【问题标题】:What are the tasks of the "reader" during Lisp interpretation?Lisp解释过程中“读者”的任务是什么?
【发布时间】:2010-12-27 09:43:16
【问题描述】:

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

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

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

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

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

谢谢!

【问题讨论】:

    标签: clojure lisp compilation interpreter


    【解决方案1】:

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

    printer 则相反:它获取 Lisp 数据并将其作为字符流输出。因此它也可以将 Lisp 数据打印到外部 s 表达式中。

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

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

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

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

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

    在某些 Lisp 方言中,阅读器是可编程的和表驱动的(通过所谓的阅读表)。此读取表包含字符的读取器函数。例如,quote ' 字符绑定到一个函数,该函数读取一个表达式并返回 (list 'quote expression) 的值。数字字符 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]
    

    所以它需要一个 test-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 表达式,计算 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 表单被评估之前运行(例如通过解释或通过编译和执行它)。

    【讨论】:

    • 感谢您的澄清。所以,有人可能会说,读者读入的程序数据是纯文本结构的 S 表达式,并返回一个 Lisp 数据结构。它不评估任何这些表达式,而只是以一种可以有效评估的方式在内存中表示它们?我现在更清楚地看到了评估器(根据 SICP 的“元循环抽象”一章,其中介绍了一个简单的 lisp-in-lisp 评估器)和成熟的解释器之间的区别。
    • @Andrew:对。一般来说,读者不会评价事物。它只是为 s 表达式创建一个 Lisp 数据结构。现在评估器可以解释这些内部数据结构 - 词法分析器阶段已经完成。通常这些程序作为数据在中间步骤中被编译成机器码或字节码。另请注意,例如 Common Lisp 阅读器具有评估事物的功能。 '(1 2 #.(+ 1 2)) 返回 (1 2 3)。 #.是一个读取器宏,它在读取时计算下一个表达式。还可以通过读取表实现其他行为。
    猜你喜欢
    • 1970-01-01
    • 2011-09-14
    • 1970-01-01
    • 1970-01-01
    • 2018-08-13
    • 2016-05-10
    • 1970-01-01
    • 1970-01-01
    • 2014-11-01
    相关资源
    最近更新 更多