读取-求值-输出循环
此条目包含过多行话或专业术语,可能需要简化或提出进一步解释。 (2018年4月20日) |
此条目没有列出任何参考或来源。 (2018年4月20日) |
“读取-求值-输出”循环(英语:Read-Eval-Print Loop,简称REPL),也被称做交互式顶层构件(英语:interactive toplevel),是一个简单的,交互式的编程环境。这个词常常用于指代一个Lisp的交互式开发环境,也能指代命令行的模式。
概述
编辑“读入-求值-输出”循环 的名字来自于以下几个Lisp用来实现这种机制的内置函数:
- 读入函数接收一个来自于用户的表达式,将其解析成数据结构并存入记忆体。例如,用户可能会输入一个s-表达式
(+ 1 2 3)
,这句话会被解析成一个包含四个元素的链表。 - 求值函数 负责处理内部的数据结构并对其求值。在Lisp中,求一个以函数名开头的s-表达式意味着对接下来的参数调用那个函数。所以函数"
+
"被在参数1 2 3
上调用,产生结果6
。 - 输出函数接受求值结果,并将其呈现给用户。尽管当前的结果“
6
”并不具有复杂的格式,但如果是一个较为复杂的表达式,那么它将会被精心处理,以便于更方便地被理解。
REPL使得探索性的编程和调试更加便捷,因为“读取-求值-输出”循环通常会比经典的“编辑-编译-运行-调试”模式要更快。
优点
编辑REPL对于学习一门新的编程语言具有很大的帮助,因为它能立刻对初学者做出回应。许多工具集和编程语言使用REPL研究算法、进行调试,比如MATLAB,ROOT(页面存档备份,存于互联网档案馆),SciPy和IPython。Python的doctest模块能够通过捕捉自身REPL命令行的输出使测试代码更容易地进行。
由于 print
函数输出的数据格式(字符串)与用户输入的数据格式(字符串)相同,大多数输出的结果也可以被带回到 read
函数作为输入。然而,有的时候输出的结果只能代表求值结果而不是求值结果本身,比如一个socket句柄或一些类的实例。比如在Python中使用 <__模块名__.类名 实例名>
这种形式来代表一个实例本身,在Common Lisp当中就使用 #<whatever>
的形式。而在CLIM,SLIME以及Symbolics Lisp Machine的REPL却有办法读取很难被完全字符串化的这些对象。他们记录被输出过的对象,之后当代码被读取时,这些对象能够被解析并重新被使用。
实现
编辑为了实现一个 Lisp REPL,只需要实现这三个函数和一个不停轮询的函数即可(当然,求值函数的实现是最为复杂的,因为它在内部要实现像 car
与 +
的原始函数以及像if
一样的特殊操作符)。这些工作完成了之后,一个基本的REPL就可以用如下的简单形式表达:(loop (print (eval (read))))
。
一种实现eval
的方式就是实现一个递归处理抽象语法树(该语法树被 read
函数创建)的函数。另一种可行的方法是将这个抽象语法树编译为机器码并执行。
主要的REPL编程语言环境
编辑APL、BASIC、Clojure、F#、Haskell、J、Julia、Perl、PHP、Prolog、Python、R、Ruby、Scala、Smalltalk、Standard ML、Swift、Tcl、Javascript、Java(自JDK 9起)