为什么Common Lisp的打印输出先于换行符后跟一个空格?

JoL*_*JoL 3 lisp common-lisp

Common Lisp Hyperspec页面print提到:

print就像prin1一样,除了对象的打印表示前面有换行符后跟一个空格.

这是我第一次看到这样的函数,并且在我第一次使用它时它就让我离开了,因为我从未想到具有这种通用名称的函数可能包含一个不常见的特性.

我正在寻找原因.我知道这可能仅仅是因为那是另一个常见的lisp可能会如何做到这一点,而common-lisp只是简单地采用了它,但如果是这样的话,我正在寻找其他 lisp 的设计理由.

我想这可能与确保输出总是可以read直接读取有关print.虽然我更喜欢这个换行符,但我可以猜测尾随空格可能是这样的,在流中,read可以知道它是一个对象的结尾并立即返回它而不必等待其余的流(以下prints).但是,我仍然无法弄清楚前一行换行背后的目的.

我一直在浏览HyperSpec,但我找不到提到的理由.

编辑:

我查看了Common-Lisp的前辈,特别是InterLisp,MacLisp和MacLisp的前身Lisp 1.5.

Interlisp(本pdf中的第145页)和Lisp 1.5(此pdf中的第140页)print功能打印对象后跟换行符.

似乎MacLisp引入了这种差异.我在原始参考手册中没有找到原因,我在本修订的参考手册中只找到了以下内容:

与PRIN1一样,PRINT以READ可以理解的形式输出对象到文件.但是,对象的输出前面是换行符,后跟一个空格,这样就可以重复调用PRINT,而不会让一个对象的结尾进入下一个对象的开头.

当然,原始定义中的尾部换行符就足够了,所以这个理由似乎没有用.

编辑2:

正如Rainer Joswig的回答所示,似乎这一变化出现在MacLisp之前的Lisp 1.6中.

Rai*_*wig 5

参见例如:PDP-6 LISP(LISP 1.6)修订版.(1967年1月)

我的猜测是,这种变体PRINT(写入换行符,然后是可读格式的s表达式,然后是空格)进入了Lisp的MIT分支,因为它在Read Eval Print Loop中使用.见上文第1页和第17页.从PDP-6 Lisp 1.6开始,它进入了当时称为Maclisp及其后的版本.

Jon L White会知道的.

查看REPL的示例,读取eval PRINT循环,在第1页.这里我使用LispWorks Lisp侦听器,其中最后一个右括号已经READ接受s-expression并且不需要进一步输入:

CL-USER 25 > (PROG NIL
               A
               (TERPRI)
               (PRINT (EVAL (READ)))
               (GO A))

(+ 12 12)
24 
(+ 45 (*
       34
       12
       12))
4941 
Run Code Online (Sandbox Code Playgroud)

每个结果都是独立的.这是顺便说一句.也像MIT Lisp机器上的交互一样 - 最后一个右括号输入s-expression,表达式被计算并且值被打印.

现在假设它被定义为不首先打印换行符:

CL-USER 27 > (PROG NIL
               A
               (TERPRI)
               (PRIN1 (EVAL (READ)))
               (terpri)
               (GO A))

(+ 1 2)3

(* 23 (+ 1
         1
         3))115
Run Code Online (Sandbox Code Playgroud)

结果将在最后一个右括号后直接打印.

Peter Norvig在他的着作"人工智能编程范式"(第231/232页)中给出了同样的推理(用户dkim指出):

但是,在Lisp中,函数print在要打印的对象之前放置一个换行符,然后放入一个空格....在UNIX中只有一个合理的策略,因为UNIX解释器(shell)的所有输入都是由换行符终止的,因此不需要newline-before.但是,在某些Lisp解释器中,输入可以通过匹配的右括号来终止.在这种情况下,需要newline-before,以免输出与输入显示在同一行.

  • 引自PAIP:"但是,在Lisp中,函数`print`在要打印的对象之前放置一个换行符,后面放一个空格....在UNIX中只有一个合理的策略,因为所有输入都是UNIX解释器(shell)由换行符终止,因此不需要newline-before.但是,在某些Lisp解释器中,输入可以通过匹配的右括号来终止.在这种情况下,需要newline-before,以免输出与输入显示在同一行." (3认同)