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)中,根本没有互动性。     

要回复问题请先登录注册