I've encounter a following statement by Richard Stallman:
我遇到了理查德·斯托尔曼的一句话:
'When you start a Lisp system, it enters a read-eval-print loop. Most other languages have nothing comparable to read, nothing comparable to eval, and nothing comparable to print. What gaping deficiencies! '
当你启动一个Lisp系统时,它会进入一个读取-读取-打印循环。大多数其他语言都没有可读的东西,也没有可与eval相媲美的东西,也没有可与print相媲美的东西。什么巨大的缺陷!”
Now, I did very little programming in Lisp, but I've wrote considerable amount of code in Python and recently a little in Erlang. My impression was that these languages also offer read-eval-print loop, but Stallman disagrees (at least about Python):
现在,我很少用Lisp编程,但我已经用Python编写了大量代码,最近还用Erlang编写了一些代码。我的印象是,这些语言也提供了“读取-运行-打印”循环,但Stallman不同意(至少在Python方面):
'I skimmed documentation of Python after people told me it was fundamentally similar to Lisp. My conclusion is that that is not so. When you start Lisp, it does 'read', 'eval', and 'print', all of which are missing in Python.'
在别人告诉我Python的基本原理与Lisp相似之后,我略去了Python的文档。我的结论是,事实并非如此。当您启动Lisp时,它会“读取”、“eval”和“print”,所有这些在Python中都没有。
Is there really a fundamental technical difference between Lisp's and Python's read-eval-print loops? Can you give examples of things that Lisp REPL makes easy and that are difficult to do in Python?
Lisp的读写打印循环和Python的读写打印循环之间真的有根本的技术差异吗?您能举一些例子说明Lisp REPL使之变得容易,而在Python中很难做到的事情吗?
4 个解决方案
#1
55
In support of Stallman's position, Python does not do the same thing as typical Lisp systems in the following areas:
在支持Stallman的位置时,Python在以下方面不做与典型的Lisp系统相同的事情:
-
The
read
function in Lisp reads an S-expression, which represents an arbitrary data structure that can either be treated as data, or evaluated as code. The closest thing in Python reads a single string, which you would have to parse yourself if you want it to mean anything.Lisp中的read函数读取一个s表达式,该表达式表示可以作为数据处理的任意数据结构,也可以作为代码进行计算。Python中最接近的东西是读取单个字符串,如果您希望它有任何含义,那么您必须自己解析它。
-
The
eval
function in Lisp can execute any Lisp code. Theeval
function in Python evaluates only expressions, and needs theexec
statement to run statements. But both these work with Python source code represented as text, and you have to jump through a bunch of hoops to "eval" a Python AST.Lisp中的eval函数可以执行任何Lisp代码。Python中的eval函数只计算表达式,并需要exec语句来运行语句。但是,这两种方法都使用以文本形式表示的Python源代码,并且您必须跳过一大堆限制,以“eval”Python AST。
-
The
print
function in Lisp writes out an S-expression in exactly the same form thatread
accepts.print
in Python prints out something defined by the data you're trying to print, which is certainly not always reversible.Lisp中的print函数以read所接受的格式写出一个s表达式。在Python中打印出由您要打印的数据定义的东西,这当然不是总是可逆的。
Stallman's statement is a bit disingenuous, because clearly Python does have functions named exactly eval
and print
, but they do something different (and inferior) to what he expects.
Stallman的说法有点不真诚,因为显然Python确实有命名为eval和print的函数,但它们的功能与他期望的有所不同(而且不如)。
In my opinion, Python does have some aspects similar to Lisp, and I can understand why people might have recommended that Stallman look into Python. However, as Paul Graham argues in What Made Lisp Different, any programming language that includes all the capabilities of Lisp, must also be Lisp.
在我看来,Python确实有一些类似于Lisp的方面,我可以理解为什么人们会建议Stallman研究Python。但是,正如Paul Graham在Lisp与众不同的地方所言,任何包含Lisp所有功能的编程语言都必须是Lisp。
#2
27
Stallman's point is that not implementing an explicit "reader" makes Python's REPL appear crippled compared to Lisps because it removes a crucial step from the REPL process. Reader is the component that transforms a textual input stream into the memory — think of something like an XML parser built into the language and used for both source code and for data. This is useful not only for writing macros (which would in theory be possible in Python with the ast
module), but also for debugging and introspection.
Stallman的观点是,没有实现显式的“读取器”会使Python的REPL与Lisps相比显得很糟糕,因为它从REPL进程中删除了一个关键步骤。Reader是将文本输入流转换为内存的组件——可以将XML解析器构建到语言中,并用于源代码和数据。这不仅对于编写宏非常有用(理论上在Python中可以使用ast模块),而且对于调试和自省也很有用。
Say you're interested in how the incf
special form is implemented. You can test it like this:
假设您对incf特殊表单的实现方式感兴趣。你可以这样测试它:
[4]> (macroexpand '(incf a))
(SETQ A (+ A 1)) ;
But incf
can do much more than incrementing symbol values. What exactly does it do when asked to increment a hash table entry? Let's see:
但是,incf可以做的不仅仅是增加符号值。当被要求增加哈希表条目时,它究竟做什么?让我们来看看:
[2]> (macroexpand '(incf (gethash htable key)))
(LET* ((#:G3069 HTABLE) (#:G3070 KEY) (#:G3071 (+ (GETHASH #:G3069 #:G3070) 1)))
(SYSTEM::PUTHASH #:G3069 #:G3070 #:G3071)) ;
Here we learn that incf
calls a system-specific puthash
function, which is an implementation detail of this Common Lisp system. Note how the "printer" is making use of features known to the "reader", such as introducing anonymous symbols with the #:
syntax, and referring to the same symbols within the scope of the expanded expression. Emulating this kind of inspection in Python would be much more verbose and less accessible.
这里我们了解到,incf调用特定于系统的puthash函数,这是这个公共Lisp系统的实现细节。请注意“打印机”如何利用“阅读器”所知道的特性,例如使用#:语法引入匿名符号,并在扩展表达式的范围内引用相同的符号。在Python中模拟这种检查会更加冗长,也更难访问。
In addition to the obvious uses at the REPL, experienced Lispers use print
and read
in the code as a simple and readily available serialization tool, comparable to XML or json. While Python has the str
function, equivalent to Lisp's print
, it lacks the equivalent of read
, the closest equivalent being eval
. eval
of course conflates two different concepts, parsing and evaluation, which leads to problems like this and solutions like this and is a recurring topic on Python forums. This would not be an issue in Lisp precisely because the reader and the evaluator are cleanly separated.
除了REPL上的明显用途之外,经验丰富的Lispers使用print并在代码中阅读,作为简单易用的序列化工具,可与XML或json相媲美。虽然Python具有与Lisp的打印相当的str函数,但它缺少与读取的等效值,最接近于eval。eval当然合并了两个不同的概念,解析和评估,这将导致类似这样的问题和类似这样的解决方案,并且是Python论坛上反复出现的主题。这不会是Lisp中的一个问题,因为读者和评价者是完全分离的。
Finally, advanced features of the reader facility enable the programmer to extend the language in ways that even macros could not otherwise provide. A perfect example of such making hard things possible is the infix
package by Mark Kantrowitz, implementing a full-featured infix syntax as a reader macro.
最后,读者工具的高级特性使程序员能够以即使是宏也无法提供的方式扩展语言。Mark Kantrowitz的中缀包就是一个很好的例子,它实现了一个完整的中缀语法作为一个阅读器宏。
#3
18
In a Lisp-based system one typically develops the program while it is running from the REPL (read eval print loop). So it integrates a bunch of tools: completion, editor, command-line-interpreter, debugger, ... The default is to have that. Type an expression with an error - you are in another REPL level with some debugging commands enabled. You actually have to do something to get rid of this behavior.
在基于lisp的系统中,通常在程序从REPL(读eval print循环)运行时开发它。因此它集成了一堆工具:完成、编辑器、命令行解释器、调试器、……默认情况下是这样的。输入一个错误的表达式——您在另一个REPL级别上,并启用了一些调试命令。你需要做一些事情来摆脱这种行为。
You can have two different meanings of the REPL concept:
REPL概念有两种不同的含义:
-
the Read Eval Print Loop like in Lisp (or a few other similar languages). It reads programs and data, it evaluates and prints the result data. Python does not work this way. Lisp's REPL allows you to work directly in a meta-programming way, writing code which generates (code), check the expansions, transform actual code, etc.. Lisp has read/eval/print as the top loop. Python has something like readstring/evaluate/printstring as the top-loop.
读Eval打印循环,如Lisp(或其他一些类似的语言)。它读取程序和数据,计算并打印结果数据。Python不是这样工作的。Lisp的REPL允许您直接使用元编程方式,编写生成(代码)的代码、检查扩展、转换实际代码等。Lisp将读取/eval/打印作为*循环。Python的顶部循环类似于readstring/evaluate/printstring。
-
the Command Line Interface. An interactive shell. See for example for IPython. Compare that to Common Lisp's SLIME.
命令行接口。交互式shell。例如,参见IPython。比较一下普通Lisp的黏液。
The default shell of Python in default mode is not really that powerful for interactive use:
默认模式下的Python默认shell对于交互使用并不是那么强大:
Python 2.7.2 (default, Jun 20 2012, 16:23:33)
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a+2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>>
You get an error message and that's it.
你会得到一个错误信息。
Compare that to the CLISP REPL:
与CLISP REPL比较:
rjmba:~ joswig$ clisp
i i i i i i i ooooo o ooooooo ooooo ooooo
I I I I I I I 8 8 8 8 8 o 8 8
I \ `+' / I 8 8 8 8 8 8
\ `-+-' / 8 8 8 ooooo 8oooo
`-__|__-' 8 8 8 8 8
| 8 o 8 8 o 8 8
------+------ ooooo 8oooooo ooo8ooo ooooo 8
Welcome to GNU CLISP 2.49 (2010-07-07) <http://clisp.cons.org/>
Copyright (c) Bruno Haible, Michael Stoll 1992, 1993
Copyright (c) Bruno Haible, Marcus Daniels 1994-1997
Copyright (c) Bruno Haible, Pierpaolo Bernardi, Sam Steingold 1998
Copyright (c) Bruno Haible, Sam Steingold 1999-2000
Copyright (c) Sam Steingold, Bruno Haible 2001-2010
Type :h and hit Enter for context help.
[1]> (+ a 2)
*** - SYSTEM::READ-EVAL-PRINT: variable A has no value
The following restarts are available:
USE-VALUE :R1 Input a value to be used instead of A.
STORE-VALUE :R2 Input a new value for A.
ABORT :R3 Abort main loop
Break 1 [2]>
CLISP uses Lisp's condition system to break into a debugger REPL. It presents some restarts. Within the error context, the new REPL provides extended commands.
CLISP使用Lisp的条件系统进入调试器REPL。它提出了重启。在错误上下文中,新的REPL提供了扩展命令。
Let's use the :R1
restart:
让我们使用:R1重新启动:
Break 1 [2]> :r1
Use instead of A> 2
4
[3]>
Thus you get interactive repair of programs and execution runs...
这样,您就可以交互式地修复程序并运行执行……
#4
5
Python's interactive mode differs from Python's "read code from file" mode in several, small, crucial ways, probably inherent in the textual representation of the language. Python is also not homoiconic, something that makes me call it "interactive mode" rather than "read-eval-print loop". That aside, I'd say that it is more a difference of grade than a difference in kind.
Python的交互模式与Python的“从文件中读取代码”模式在几个很小的、关键的方面有所不同,可能是语言的文本表示所固有的。Python也不是纯图标,这让我把它称为“交互模式”,而不是“读取-事件-打印循环”。除此之外,我要说的是,这更多的是等级的不同而不是种类的不同。
Now, something tahtactually comes close to "difference in kind", in a Python code file, you can easily insert blank lines:
现在,在Python代码文件中,tahtt实际上接近于“种类上的差异”,您可以轻松地插入空行:
def foo(n):
m = n + 1
return m
If you try to paste the identical code into the interpreter, it will consider the function to be "closed" and complain that you have a naked return statement at the wrong indentation. This does not happen in (Common) Lisp.
如果您试图将相同的代码粘贴到解释器中,它会认为函数是“关闭的”,并抱怨您在错误的缩进处有一个裸返回语句。这在(常见的)Lisp中是不会发生的。
Furthermore, there are some rather handy convenience variables in Common Lisp (CL) that are not available (at least as far as I know) in Python. Both CL and Python have "value of last expression" (*
in CL, _
in Python), but CL also has **
(value of expression before last) and ***
(the value of the one before that) and +
, ++
and +++
(the expressions themselves). CL also doesn't distinguish between expressions and statements (in essence, everything is an expression) and all of that does help build a much richer REPL experience.
此外,在公共Lisp (CL)中有一些非常方便的变量(至少就我所知)在Python中是不可用的。CL和Python都有“最后一个表达式的值”(CL中的*,Python中的_),但是CL也有**(前一个表达式的值)和***(前一个表达式的值)以及+++ +++ +++(表达式本身)。CL也不区分表达式和语句(本质上,所有东西都是一个表达式),所有这些都有助于构建更丰富的REPL体验。
As I said at the beginning, it is more a difference in grade than difference in kind. But had the gap been only a smidgen wider between them, it would probably be a difference in kind, as well.
正如我在一开始说的,这更多的是成绩的不同而不是种类的不同。但是如果他们之间的差距再大一点,那么他们之间的性质也会有所不同。
#1
55
In support of Stallman's position, Python does not do the same thing as typical Lisp systems in the following areas:
在支持Stallman的位置时,Python在以下方面不做与典型的Lisp系统相同的事情:
-
The
read
function in Lisp reads an S-expression, which represents an arbitrary data structure that can either be treated as data, or evaluated as code. The closest thing in Python reads a single string, which you would have to parse yourself if you want it to mean anything.Lisp中的read函数读取一个s表达式,该表达式表示可以作为数据处理的任意数据结构,也可以作为代码进行计算。Python中最接近的东西是读取单个字符串,如果您希望它有任何含义,那么您必须自己解析它。
-
The
eval
function in Lisp can execute any Lisp code. Theeval
function in Python evaluates only expressions, and needs theexec
statement to run statements. But both these work with Python source code represented as text, and you have to jump through a bunch of hoops to "eval" a Python AST.Lisp中的eval函数可以执行任何Lisp代码。Python中的eval函数只计算表达式,并需要exec语句来运行语句。但是,这两种方法都使用以文本形式表示的Python源代码,并且您必须跳过一大堆限制,以“eval”Python AST。
-
The
print
function in Lisp writes out an S-expression in exactly the same form thatread
accepts.print
in Python prints out something defined by the data you're trying to print, which is certainly not always reversible.Lisp中的print函数以read所接受的格式写出一个s表达式。在Python中打印出由您要打印的数据定义的东西,这当然不是总是可逆的。
Stallman's statement is a bit disingenuous, because clearly Python does have functions named exactly eval
and print
, but they do something different (and inferior) to what he expects.
Stallman的说法有点不真诚,因为显然Python确实有命名为eval和print的函数,但它们的功能与他期望的有所不同(而且不如)。
In my opinion, Python does have some aspects similar to Lisp, and I can understand why people might have recommended that Stallman look into Python. However, as Paul Graham argues in What Made Lisp Different, any programming language that includes all the capabilities of Lisp, must also be Lisp.
在我看来,Python确实有一些类似于Lisp的方面,我可以理解为什么人们会建议Stallman研究Python。但是,正如Paul Graham在Lisp与众不同的地方所言,任何包含Lisp所有功能的编程语言都必须是Lisp。
#2
27
Stallman's point is that not implementing an explicit "reader" makes Python's REPL appear crippled compared to Lisps because it removes a crucial step from the REPL process. Reader is the component that transforms a textual input stream into the memory — think of something like an XML parser built into the language and used for both source code and for data. This is useful not only for writing macros (which would in theory be possible in Python with the ast
module), but also for debugging and introspection.
Stallman的观点是,没有实现显式的“读取器”会使Python的REPL与Lisps相比显得很糟糕,因为它从REPL进程中删除了一个关键步骤。Reader是将文本输入流转换为内存的组件——可以将XML解析器构建到语言中,并用于源代码和数据。这不仅对于编写宏非常有用(理论上在Python中可以使用ast模块),而且对于调试和自省也很有用。
Say you're interested in how the incf
special form is implemented. You can test it like this:
假设您对incf特殊表单的实现方式感兴趣。你可以这样测试它:
[4]> (macroexpand '(incf a))
(SETQ A (+ A 1)) ;
But incf
can do much more than incrementing symbol values. What exactly does it do when asked to increment a hash table entry? Let's see:
但是,incf可以做的不仅仅是增加符号值。当被要求增加哈希表条目时,它究竟做什么?让我们来看看:
[2]> (macroexpand '(incf (gethash htable key)))
(LET* ((#:G3069 HTABLE) (#:G3070 KEY) (#:G3071 (+ (GETHASH #:G3069 #:G3070) 1)))
(SYSTEM::PUTHASH #:G3069 #:G3070 #:G3071)) ;
Here we learn that incf
calls a system-specific puthash
function, which is an implementation detail of this Common Lisp system. Note how the "printer" is making use of features known to the "reader", such as introducing anonymous symbols with the #:
syntax, and referring to the same symbols within the scope of the expanded expression. Emulating this kind of inspection in Python would be much more verbose and less accessible.
这里我们了解到,incf调用特定于系统的puthash函数,这是这个公共Lisp系统的实现细节。请注意“打印机”如何利用“阅读器”所知道的特性,例如使用#:语法引入匿名符号,并在扩展表达式的范围内引用相同的符号。在Python中模拟这种检查会更加冗长,也更难访问。
In addition to the obvious uses at the REPL, experienced Lispers use print
and read
in the code as a simple and readily available serialization tool, comparable to XML or json. While Python has the str
function, equivalent to Lisp's print
, it lacks the equivalent of read
, the closest equivalent being eval
. eval
of course conflates two different concepts, parsing and evaluation, which leads to problems like this and solutions like this and is a recurring topic on Python forums. This would not be an issue in Lisp precisely because the reader and the evaluator are cleanly separated.
除了REPL上的明显用途之外,经验丰富的Lispers使用print并在代码中阅读,作为简单易用的序列化工具,可与XML或json相媲美。虽然Python具有与Lisp的打印相当的str函数,但它缺少与读取的等效值,最接近于eval。eval当然合并了两个不同的概念,解析和评估,这将导致类似这样的问题和类似这样的解决方案,并且是Python论坛上反复出现的主题。这不会是Lisp中的一个问题,因为读者和评价者是完全分离的。
Finally, advanced features of the reader facility enable the programmer to extend the language in ways that even macros could not otherwise provide. A perfect example of such making hard things possible is the infix
package by Mark Kantrowitz, implementing a full-featured infix syntax as a reader macro.
最后,读者工具的高级特性使程序员能够以即使是宏也无法提供的方式扩展语言。Mark Kantrowitz的中缀包就是一个很好的例子,它实现了一个完整的中缀语法作为一个阅读器宏。
#3
18
In a Lisp-based system one typically develops the program while it is running from the REPL (read eval print loop). So it integrates a bunch of tools: completion, editor, command-line-interpreter, debugger, ... The default is to have that. Type an expression with an error - you are in another REPL level with some debugging commands enabled. You actually have to do something to get rid of this behavior.
在基于lisp的系统中,通常在程序从REPL(读eval print循环)运行时开发它。因此它集成了一堆工具:完成、编辑器、命令行解释器、调试器、……默认情况下是这样的。输入一个错误的表达式——您在另一个REPL级别上,并启用了一些调试命令。你需要做一些事情来摆脱这种行为。
You can have two different meanings of the REPL concept:
REPL概念有两种不同的含义:
-
the Read Eval Print Loop like in Lisp (or a few other similar languages). It reads programs and data, it evaluates and prints the result data. Python does not work this way. Lisp's REPL allows you to work directly in a meta-programming way, writing code which generates (code), check the expansions, transform actual code, etc.. Lisp has read/eval/print as the top loop. Python has something like readstring/evaluate/printstring as the top-loop.
读Eval打印循环,如Lisp(或其他一些类似的语言)。它读取程序和数据,计算并打印结果数据。Python不是这样工作的。Lisp的REPL允许您直接使用元编程方式,编写生成(代码)的代码、检查扩展、转换实际代码等。Lisp将读取/eval/打印作为*循环。Python的顶部循环类似于readstring/evaluate/printstring。
-
the Command Line Interface. An interactive shell. See for example for IPython. Compare that to Common Lisp's SLIME.
命令行接口。交互式shell。例如,参见IPython。比较一下普通Lisp的黏液。
The default shell of Python in default mode is not really that powerful for interactive use:
默认模式下的Python默认shell对于交互使用并不是那么强大:
Python 2.7.2 (default, Jun 20 2012, 16:23:33)
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a+2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>>
You get an error message and that's it.
你会得到一个错误信息。
Compare that to the CLISP REPL:
与CLISP REPL比较:
rjmba:~ joswig$ clisp
i i i i i i i ooooo o ooooooo ooooo ooooo
I I I I I I I 8 8 8 8 8 o 8 8
I \ `+' / I 8 8 8 8 8 8
\ `-+-' / 8 8 8 ooooo 8oooo
`-__|__-' 8 8 8 8 8
| 8 o 8 8 o 8 8
------+------ ooooo 8oooooo ooo8ooo ooooo 8
Welcome to GNU CLISP 2.49 (2010-07-07) <http://clisp.cons.org/>
Copyright (c) Bruno Haible, Michael Stoll 1992, 1993
Copyright (c) Bruno Haible, Marcus Daniels 1994-1997
Copyright (c) Bruno Haible, Pierpaolo Bernardi, Sam Steingold 1998
Copyright (c) Bruno Haible, Sam Steingold 1999-2000
Copyright (c) Sam Steingold, Bruno Haible 2001-2010
Type :h and hit Enter for context help.
[1]> (+ a 2)
*** - SYSTEM::READ-EVAL-PRINT: variable A has no value
The following restarts are available:
USE-VALUE :R1 Input a value to be used instead of A.
STORE-VALUE :R2 Input a new value for A.
ABORT :R3 Abort main loop
Break 1 [2]>
CLISP uses Lisp's condition system to break into a debugger REPL. It presents some restarts. Within the error context, the new REPL provides extended commands.
CLISP使用Lisp的条件系统进入调试器REPL。它提出了重启。在错误上下文中,新的REPL提供了扩展命令。
Let's use the :R1
restart:
让我们使用:R1重新启动:
Break 1 [2]> :r1
Use instead of A> 2
4
[3]>
Thus you get interactive repair of programs and execution runs...
这样,您就可以交互式地修复程序并运行执行……
#4
5
Python's interactive mode differs from Python's "read code from file" mode in several, small, crucial ways, probably inherent in the textual representation of the language. Python is also not homoiconic, something that makes me call it "interactive mode" rather than "read-eval-print loop". That aside, I'd say that it is more a difference of grade than a difference in kind.
Python的交互模式与Python的“从文件中读取代码”模式在几个很小的、关键的方面有所不同,可能是语言的文本表示所固有的。Python也不是纯图标,这让我把它称为“交互模式”,而不是“读取-事件-打印循环”。除此之外,我要说的是,这更多的是等级的不同而不是种类的不同。
Now, something tahtactually comes close to "difference in kind", in a Python code file, you can easily insert blank lines:
现在,在Python代码文件中,tahtt实际上接近于“种类上的差异”,您可以轻松地插入空行:
def foo(n):
m = n + 1
return m
If you try to paste the identical code into the interpreter, it will consider the function to be "closed" and complain that you have a naked return statement at the wrong indentation. This does not happen in (Common) Lisp.
如果您试图将相同的代码粘贴到解释器中,它会认为函数是“关闭的”,并抱怨您在错误的缩进处有一个裸返回语句。这在(常见的)Lisp中是不会发生的。
Furthermore, there are some rather handy convenience variables in Common Lisp (CL) that are not available (at least as far as I know) in Python. Both CL and Python have "value of last expression" (*
in CL, _
in Python), but CL also has **
(value of expression before last) and ***
(the value of the one before that) and +
, ++
and +++
(the expressions themselves). CL also doesn't distinguish between expressions and statements (in essence, everything is an expression) and all of that does help build a much richer REPL experience.
此外,在公共Lisp (CL)中有一些非常方便的变量(至少就我所知)在Python中是不可用的。CL和Python都有“最后一个表达式的值”(CL中的*,Python中的_),但是CL也有**(前一个表达式的值)和***(前一个表达式的值)以及+++ +++ +++(表达式本身)。CL也不区分表达式和语句(本质上,所有东西都是一个表达式),所有这些都有助于构建更丰富的REPL体验。
As I said at the beginning, it is more a difference in grade than difference in kind. But had the gap been only a smidgen wider between them, it would probably be a difference in kind, as well.
正如我在一开始说的,这更多的是成绩的不同而不是种类的不同。但是如果他们之间的差距再大一点,那么他们之间的性质也会有所不同。