Lisp是REPL唯一的语言吗?

Eli*_*der 19 lisp programming-languages scala read-eval-print-loop

除了Lisp(ruby,scala)之外还有其他语言表示他们使用REPL(读取,评估,打印,循环),但不清楚REPL的含义是否与Lisp中的相同.Lisp REPL与非Lisp REPL有何不同?

Rai*_*wig 33

REPL的想法来自Lisp社区.还有其他形式的文本交互式界面,例如命令行界面.一些文本接口还允许执行某种编程语言的子集.

REPL代表READ EVAL PRINT LOOP :(循环(打印(eval(读取)))).

在Lisp中,REPL不是命令行解释器(CLI).READ不读取命令,REPL不执行命令.READ读取输入并将其转换为数据.因此该READ函数可以读取所有类型的s表达式 - 而不仅仅是Lisp代码.

READ读取s表达式.这是一种也支持编码源代码的数据格式.READ返回Lisp数据.

EVAL以Lisp数据的形式获取Lisp源代码并对其进行评估.副作用可能发生,EVAL返回一个或多个值.未定义如何使用解释器或编译器实现EVAL.实现使用不同的策略.

PRINT获取Lisp数据并将其打印为s表达式.

LOOP只围绕这个循环.在现实生活中,REPL更复杂,包括错误处理和子循环,即所谓的中断循环.如果出现错误,则会在错误的上下文中添加另一个REPL,并添加调试命令.在一次迭代中产生的值也可以重新用作下一次评估的输入.

由于Lisp都使用代码作为数据和功能元素,因此与其他编程语言略有不同.

类似的语言也提供类似的交互式界面.例如,Smalltalk也允许交互式执行,但它不像Lisp那样使用I/O的数据格式.任何Ruby/Python/...交互式界面都是如此.

题:

那么阅读EXPRESSIONS,评估它们和打印它们的价值观的最初想法有多重要?这对于其他语言的作用是否重要:阅读文本,解析文本,执行文章,打印内容以及可选择打印返回值?通常不会真正使用返回值.

所以有两种可能的答案:

  1. 一个Lisp REPL与大多数其他文本交互界面不同,因为它基于s表达式的数据I/O的概念并对它们进行评估.

  2. REPL是描述编程语言实现或其子集的文本交互式接口的通用术语.

在实际实现中,Lisp REPL具有复杂的实现并提供许多服务,直到输入和输出对象的可点击演示(Symbolics,CLIM,SLIME).高级REPL实现例如在SLIME(一种流行的基于Emacs的Common Lisp IDE),LispWorksAllegro 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)))
Run Code Online (Sandbox Code Playgroud)

订单,产品清单和金额:

CL-USER 2 > '((3 shoe) (4 cap))
((3 SHOE) (4 CAP))
Run Code Online (Sandbox Code Playgroud)

订单的价格*是包含最后一个REPL值的变量.它不包含此值作为字符串,而是包含真实的实际数据.

CL-USER 3 > (loop for (n product) in *
                  sum (* n (first (second (find product *products*
                                                :key 'first)))))
340
Run Code Online (Sandbox Code Playgroud)

但是你也可以计算Lisp代码:

我们来看一个函数,它可以添加两个参数的方块:

CL-USER 4 > '(defun foo (a b) (+ (* a a) (* b b))) 
(DEFUN FOO (A B) (+ (* A A) (* B B)))
Run Code Online (Sandbox Code Playgroud)

第四个元素就是算术表达式.*指的是最后一个值:

CL-USER 5 > (fourth *)
(+ (* A A) (* B B))
Run Code Online (Sandbox Code Playgroud)

现在我们在它周围添加一些代码来绑定变量ab一些数字.我们使用Lisp函数LIST创建一个新列表.

CL-USER 6 > (list 'let '((a 12) (b 10)) *)
(LET ((A 12) (B 10)) (+ (* A A) (* B B)))
Run Code Online (Sandbox Code Playgroud)

然后我们评估上面的表达式.再次,*指的是最后一个值.

CL-USER 7 > (eval *)
244
Run Code Online (Sandbox Code Playgroud)

每个REPL交互都会更新几个变量.示例是*,**以及***之前的值.还有+以前的输入.这些变量的值不是字符串,而是数据对象.+将包含REPL的读操作的最后结果.例:

变量的价值是*print-length*多少?

CL-USER 8 > *print-length*
NIL
Run Code Online (Sandbox Code Playgroud)

让我们看看如何读取和打印列表:

CL-USER 9 > '(1 2 3 4 5)
(1 2 3 4 5)
Run Code Online (Sandbox Code Playgroud)

现在让我们将上面的符号设置*print-length*为3. ++引用第二个先前的输入读取,作为数据.SET设置符号值.

CL-USER 10 > (set ++ 3)
3
Run Code Online (Sandbox Code Playgroud)

然后上面的列表打印不同.**指的是前面的第二个结果 - 数据,而不是文本.

CL-USER 11 > **
(1 2 3 ...)
Run Code Online (Sandbox Code Playgroud)


Alb*_*ien 12

看作REPL的概念就是只读,Eval,Print和Loop,对于许多语言都有REPL并不令人惊讶:

C/C++

C#/ LINQ

二郎神

Haskell(在Windows上)

Java的

使用Javascript

Perl的

蟒蛇

红宝石

斯卡拉

Smalltalk - 我在REPL上学到了它!

编辑我忘记了Java!

  • [GHCi](http://www.haskell.org/ghc/docs/7.0.3/html/users_guide/ghci.html)适用于GHC支持的任何平台.WinGHCi只是一个gui前端. (7认同)
  • 以利:我从未听过有人这么说过.你应该问他们. (2认同)

Dan*_*ral 5

我认为比较两种方法很有意思.Lisp系统中的裸骨REPL循环如下所示:

(loop (print (eval (read))))
Run Code Online (Sandbox Code Playgroud)

以下是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
;
Run Code Online (Sandbox Code Playgroud)

Lisp和Forth做了完全不同的事情,特别是在EVAL部分,但也在PRINT部分.然而,它们共享,在两种语言的程序是通过将它的源代码,以各自的循环运行的事实,并在这两种情况下的代码只是数据(尽管在第四情况下,它更像是数据也代码).

我怀疑任何人只说LISP有一个REPL是READ循环读取DATA,由EVAL解析,并创建一个程序,因为CODE也是DATA.这种区别在许多方面都很有趣,关于Lisp和其他语言之间的区别,但就REPL而言,它根本不重要.

让我们从外面考虑这个:

  1. READ - 从stdin返回输入
  2. EVAL - 将输入表示为语言中的表达式
  3. 打印 - 打印EVAL的结果
  4. 循环 - 回到READ

没有进入实现细节,人们无法区分Lisp REPL,例如,Ruby REPL.作为功​​能,它们是相同的.