如何解决Lisp是REPL的唯一语言吗?
| 除了Lisp(红宝石,斯卡拉)以外,还有其他语言说它们使用REPL(读,评估,打印,循环),但是目前还不清楚REPL的含义是否与Lisp相同。 Lisp REPL与非Lisp REPL有何不同?解决方法
REPL的想法来自Lisp社区。还有其他形式的文本交互界面,例如命令行界面。一些文本界面还允许执行某种编程语言的子集。
REPL代表READ EVAL PRINT LOOP :(循环(打印(评估(读取)))))。
上面四个函数中的每一个都是原始的Lisp函数。
在Lisp中,REPL不是命令行解释器(CLI)。
READ
不读取命令,REPL不执行命令。 “ 0”以s表达式格式读取输入数据并将其转换为内部数据。因此,“ 0”函数可以读取所有类型的s表达式-而不仅仅是Lisp代码。
READ读取一个S表达式。这是一种数据格式,也支持编码源代码。 READ返回Lisp数据。
EVAL以Lisp数据的形式获取Lisp源代码并对其进行评估。可能会发生副作用,并且EVAL返回一个或多个值。没有定义如何使用解释器或编译器实现EVAL。实现使用不同的策略。
PRINT获取Lisp数据并将其作为s表达式打印到输出流。
LOOP只是在此循环。在现实生活中,REPL更为复杂,并且包括错误处理和子循环,即所谓的中断循环。在发生错误的情况下,如果发生错误,则仅获取具有附加调试命令的另一个REPL。一次迭代中产生的值也可以重新用作下一次评估的输入。
由于Lisp都使用数据编码和功能元素,因此与其他编程语言略有不同。
相似的语言也将提供相似的交互界面。例如,Smalltalk还允许交互式执行,但它不像Lisp那样对I / O使用数据格式。对于任何Ruby / Python / ...交互式界面都相同。
题:
那么,阅读,评估和打印其价值的原始思想有多重要?与其他语言相比,这是否重要:读取文本,解析文本,执行文本,选择打印某些内容以及选择打印返回值?通常,返回值并未真正使用。
因此,有两个可能的答案:
Lisp REPL与大多数其他文本交互界面不同,因为它基于s表达式的数据I / O并对其进行评估。
REPL是一个通用术语,描述了与编程语言实现或其子集相关的文本交互界面。
Lisp中的REPL
在实际的实现中,Lisp REPL具有复杂的实现并提供许多服务,直到输入和输出对象的可单击的表示形式(符号,CLIM,SLIME)。例如,高级REPL实现可在SLIME(Common Lisp的一种流行的基于Emacs的IDE),McLIM,LispWorks和Allegro CL中获得。
Lisp REPL交互的示例:
产品和价格清单:
CL-USER 1 > (setf *products* \'((shoe (100 euro))
(shirt (20 euro))
(cap (10 euro))))
((SHOE (100 EURO)) (SHIRT (20 EURO)) (CAP (10 EURO)))
订单,产品清单和金额:
CL-USER 2 > \'((3 shoe) (4 cap))
((3 SHOE) (4 CAP))
订单价格*
是包含最后一个REPL值的变量。它不包含此值作为字符串,而是实际的实际数据。
CL-USER 3 > (loop for (n product) in *
sum (* n (first (second (find product *products*
:key \'first)))))
340
但是您也可以计算Lisp代码:
让我们来看一个函数,将两个参数的平方相加:
CL-USER 4 > \'(defun foo (a b) (+ (* a a) (* b b)))
(DEFUN FOO (A B) (+ (* A A) (* B B)))
第四个元素只是算术表达式。 *
是最后一个值:
CL-USER 5 > (fourth *)
(+ (* A A) (* B B))
现在我们在其周围添加一些代码,以将变量a
和b
绑定到一些数字。我们正在使用Lisp函数ѭ12create创建一个新列表。
CL-USER 6 > (list \'let \'((a 12) (b 10)) *)
(LET ((A 12) (B 10)) (+ (* A A) (* B B)))
然后,我们评估以上表达式。同样,*
是最后一个值。
CL-USER 7 > (eval *)
244
每次ѭ16互动时,都会更新几个变量。先前的值示例为*
,**
和***
。前一个输入也有+
。这些变量的值不是字符串,而是数据对象。 +
将包含REPL读操作的最后结果。例:
变量*print-length*
的值是多少?
CL-USER 8 > *print-length*
NIL
让我们看看如何读取和打印列表:
CL-USER 9 > \'(1 2 3 4 5)
(1 2 3 4 5)
现在,将上面的符号*print-length*
设置为3。++
指的是第二个先前输入的读取数据。 SET
设置符号值。
CL-USER 10 > (set ++ 3)
3
然后上面的列表以不同的方式打印。 **
表示第二个先前的结果-数据,而不是文本。
CL-USER 11 > **
(1 2 3 ...)
,看到REPL的概念只是阅读,评估,打印和循环,就不必太惊讶许多语言都有REPL:
C / C ++
C#/ LINQ
Erlang
Haskell(在Windows上)
爪哇
Java脚本
佩尔
蟒蛇
红宝石
斯卡拉
Smalltalk-我是在REPL上学到的!
编辑我忘记了Java!
,我认为比较两种方法很有趣。 Lisp系统中的裸露REPL循环如下所示:
(loop (print (eval (read))))
这是REPL循环的两个实际的Forth实现。我在这里什么都没留下-这是这些循环的完整代码。
: DO-QUIT ( -- ) ( R: i*x -- )
EMPTYR
0 >IN CELL+ ! \\ set SOURCE-ID to 0
POSTPONE [
BEGIN \\ The loop starts here
REFILL \\ READ from standard input
WHILE
INTERPRET \\ EVALUATE what was read
STATE @ 0= IF .\" OK\" THEN \\ PRINT
CR
REPEAT
;
: quit
sp0 @ \'tib !
blk off
[compile] [
begin
rp0 @ rp!
status
query \\ READ
run \\ EVALUATE
state @ not
if .\" ok\" then \\ PRINT
again \\ LOOP
;
Lisp和Forth做的事情完全不同,特别是在EVAL部分,但在PRINT部分。但是,他们共享一个事实,两种语言的程序都是通过将其源代码提供给各自的循环来运行的,并且在两种情况下,代码都只是数据(尽管在Forth情况下,它更像是数据也在代码中)。
我怀疑有人说只有LISP具有REPL的原因是READ循环读取了由EVAL解析的DATA,并且由于CODE也是DATA而创建了一个程序。关于Lisp和其他语言之间的区别,这种区别在很多方面都很有趣,但是就REPL而言,这一点都没有关系。
让我们从外部考虑一下:
READ-从stdin返回输入
EVAL-将所述输入作为语言中的表达式进行处理
打印-打印EVAL \的结果
循环-返回读取
如果不讨论实现细节,就无法将Lisp REPL与Ruby REPL区分开。作为功能,它们是相同的。
,我猜您可能会说Scala的\“ REPL \\”是\\“ RCRPL \”:读取,编译,运行,打印。但是由于编译器会在内存中保持“高温”状态,因此对于进行中的交互来说非常快-只需几秒钟即可启动。
,许多人认为REPL的行为必须与LISP中的行为完全一样,或者它不是真正的REPL。相反,他们认为它有些不同,例如CLI(命令行解释器)。老实说,我倾向于认为它遵循以下基本流程:
读取用户的输入
评估输入
打印输出
循环回到读取
那就是REPL。如前所述,许多语言都具有上述功能。
有关此类讨论的示例,请参见此reddit线程。
,有一个名为ѭ33的不错的项目,它通过Node.JS公开了各种REPL:
https://github.com/evilhackerdude/multi-repl
如果您查看受支持的语言列表,则很显然,不仅Lisp具有REPL的概念。
clj(clojure)
ghci(ghc)
ipython的
irb(红宝石)
js(spidermonkey)
节点
蟒蛇
sbcl
v8
实际上,在Ruby中实现琐碎的事情相当容易:
repl = -> prompt { print prompt; puts(\" => %s\" % eval(gets.chomp!)) }
loop { repl[\">> \"] }
, Lisp REPL与非Lisp REPL有何不同?
让我们将Common Lisp的REPL与Python的IPython进行比较。
主要两点是:
Lisp是一种基于图像的语言。更改后,无需重新启动进程/ REPL /整个应用程序。我们按函数编译代码函数(带有编译器警告等)。
我们不放松状态。更重要的是,当我们更新类定义时,REPL中的对象也会按照我们控制的规则进行更新。这样,我们可以在正在运行的系统中热重载代码。
通常,在Python中,您启动IPython或放入ipdb。您定义一些数据,直到尝试新功能。您编辑了源代码,然后想再试一次,因此退出IPython,然后重新开始整个过程。在Lisp(主要是Common Lisp)中,根本没有互动性。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。