- 概述
在REPL中,用户输入一个或多个表达式(而不是整个编译单元),REPL评估它们并显示结果。名称read-eval-print循环来自实现此功能的Lisp原语函数的名称:
读取函数接受来自用户的表达式,并将其解析为存储器中的数据结构。例如,用户可以输入s表达式(+ 1 2 3),其被解析为包含四个数据元素的链表。
eval函数接受这个内部数据结构并对其进行计算。在Lisp中,以函数名称开始的s表达式的计算意味着对构成表达式其余部分的参数调用该函数。因此,对参数1 2 3调用函数+,得到结果6。 打印函数接收eval生成的结果,并将其打印给用户。如果它是一个复杂的表达式,它可以是漂亮的打印,使其更容易理解。在这个例子中,虽然,数字6不需要太多的格式打印。 然后开发环境返回到读状态,创建一个循环,当程序关闭时,循环终止。REPL有助于探索性编程和调试,因为程序员可以在决定为下一次读取提供什么表达式之前检查打印结果。 read-eval-print循环包括程序员比经典的编辑 - 编译 - 运行 - 调试循环更频繁。
因为打印函数以读取函数用于输入的相同文本格式输出,所以大多数结果以可以(如果有用的话)被复制并粘贴回REPL的形式打印。然而,有时需要打印不能被理解地读回的元素的表示,例如套接字句柄或复杂类实例。在这些情况下,必须存在不可读对象的语法。在Python中,它是<__ module __。class instance>符号,在Common Lisp中,#<whatever>形式。 CLIM,SLIME和Symbolics Lisp Machine的REPL也可以读回不可读对象。它们记录每个输出打印的对象。稍后当代码被读回时,将从打印输出中检索对象。
可以创建REPL以支持任何语言。对编译语言的REPL支持通常通过在提供编译器接口的虚拟机之上实现解释器来实现。用于编译语言的REPL的示例包括CINT(及其后继者Cling),Ch和BeanShell。
- 用途
几乎所有的UNIX shell都是图灵完整语言的REPL。 作为shell,除了提供对编程能力的访问之外,REPL环境允许用户访问操作系统的相关特征。
除在操作系统shell之外的REPL最常见的用途是即时原型。 其他用途包括数学计算,创建集成科学分析(例如IPython),交互式软件维护,基准测试和算法探索的文档。
REPL可以成为学习新语言的重要组成部分,因为它向新手提供快速反馈。
- 实现
要实现Lisp REPL,只需要实现这三个函数和一个无限循环函数。 (当然,eval的实现将是复杂的,因为它还必须实现所有的原始函数像car和+和特殊的操作符,如if)。这样做,一个基本的REPL本身只是一行代码:
(loop (print (eval (read))))
eval的一个可能的实现是作为递归解释器,作用于通过读取创建的抽象语法树。 另一种可能性是将语法树编译成机器码并执行它。
Lisp中的实际REPL实现通常要复杂得多。
- 功能
Lisp REPL提供的典型功能包括:
- 输入和输出的历史。
- 为输入表达式和结果设置变量。这些变量也可在REPL中使用。例如在Common Lisp *中指的是最后的结果,**和***之前的结果。
- REPL的层级。在许多Lisp系统中,如果在读取,评估或打印表达式期间发生错误,系统不会返回到顶层并显示错误消息。相反,一个新的REPL,一级更深,在错误上下文中启动。然后,用户可以检查问题,修复并继续(如果可能)。如果在这种调试REPL中发生错误,则开始另一个REPL,再一次更深一层。通常,REPL提供特殊的调试命令。
- 错误处理。 REPL提供重新启动。当发生错误以返回到某个REPL级别时,可以使用这些重新启动。
- 数据对象的鼠标敏感输入和输出。输入编辑和上下文特定完成符号,路径名,类名和其他对象。
- 命令的帮助和文档。
- 控制读写器的变量。例如,变量* read-base *控制默认情况下读取的基数。
- 控制打印机的变量。示例:要打印的表达式的最大长度或最大深度。
- 其他命令语法。一些REPL具有不遵循s表达式语法的命令,但通常使用Lisp数据作为参数。
- 图形REPL。一些Lisp REPL(CLIM监听器是一个例子)也接受图形输入和输出。
- 参考文献
hey,Tony; Pápay,Gyuri(2014)。 计算宇宙:革命之旅。 剑桥大学出版社。 p。 . ISBN ,“现代脚本语言的一个主要特征是它们的交互性,有时被称为REPL编程环境...。使用REPL环境的易用性和立即执行的特性有时 作为脚本语言的定义。
- 外部链接
Paul Graham在Common Lisp中写了一个。
JoëlFranusic 列表是用于各种编程语言的客户端web REPL。