为什么是公共Lisp';s打印输出前面是换行符,后面是空格?

为什么是公共Lisp';s打印输出前面是换行符,后面是空格?,lisp,common-lisp,Lisp,Common Lisp,提到这一点: print与prin1类似,只是对象的打印表示前面有一个换行符,后面有一个空格 这是我第一次看到这样的函数,我第一次使用它时就被它吓坏了,因为我从来没有想到一个具有如此普通名称的函数可能包含一个不常见的特性 我在寻找最初的原因。我知道这可能只是因为另一个通用lisp可能就是这样做的,而通用lisp只是采用了它,但如果是这样的话,我会在另一个lisp中寻找设计原因 我想这可能与确保输出始终可以通过read直接从print读取有关。虽然我更喜欢使用换行符,但我可以猜测,尾随空格可能是这

提到这一点:

print与prin1类似,只是对象的打印表示前面有一个换行符,后面有一个空格

这是我第一次看到这样的函数,我第一次使用它时就被它吓坏了,因为我从来没有想到一个具有如此普通名称的函数可能包含一个不常见的特性

我在寻找最初的原因。我知道这可能只是因为另一个通用lisp可能就是这样做的,而通用lisp只是采用了它,但如果是这样的话,我会在另一个lisp中寻找设计原因

我想这可能与确保输出始终可以通过
read
直接从
print
读取有关。虽然我更喜欢使用换行符,但我可以猜测,尾随空格可能是这样的:在流中,
read
可以知道它是一个对象的结尾,并立即返回它,而无需等待流的其余部分(以下
print
s)。然而,我仍然不明白这条新线背后的目的

我一直在看HyperSpec,但找不到提到的原因

编辑:

我研究了CommonLisp的前身,特别是InterLisp、MacLisp和MacLisp的前身Lisp1.5

Interlisp(第145页英寸)和Lisp 1.5(第140页英寸)
print
函数打印对象,后跟换行符

似乎是MacLisp引入了这种差异。我在原始参考手册中没有找到原因,我只发现以下几点:

和PRIN1一样,PRINT以可读的形式将对象输出到文件。但是,对象的输出前面是换行符,后面是空格,这样就可以重复调用PRINT,而不必让一个对象的结尾运行到下一个对象的开头

当然,原始定义中的尾随换行符就足够了,所以这个理由似乎不成立

编辑2:


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

基本上,这是一个仅限REPL的函数,类似于“穷人的或”

它的用例类似于

(map nil #'print list)
或者,更一般地说

(complex-traversal-map #'print weird-structure)
它在打印对象周围插入空格以避免干扰 其他调用的输出。 在过去的几十年中,释放出了什么样的空白。 它本应被称为“单独在线打印”,但必须如此 简短且容易猜测

它本质上是“遗留”功能,如。

参见示例:

我的猜测是,
PRINT
(它写一个换行符,然后是可读格式的s表达式,然后是空格)的这个变体进入了Lisp的MIT分支,因为它在Read-Eval-PRINT循环中使用。见上文第1页和第17页。从PDP-6Lisp1.6开始,它进入了后来被称为Maclisp和以后的版本

乔恩·怀特会知道的

请看第1页的REPL示例,即read eval PRINT循环。 在这里,我使用了一个LispWorks Lisp侦听器,其中最后一个右括号已经使
READ
接受s表达式,无需进一步输入:

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

(+ 12 12)
24 
(+ 45 (*
       34
       12
       12))
4941 

每个结果都有自己的一行。顺便说一句,这也和MIT Lisp机器上的交互一样——最后一个右括号进入s表达式,计算表达式并打印值

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

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

(+ 1 2)3

(* 23 (+ 1
         1
         3))115
结果将直接打印在最后一个右括号之后

彼得·诺维格(Peter Norvig)在其著作《人工智能编程范例》(Paradigms of Artificial Intelligence Programming,第231/232页)中给出了同样的推理(如用户dkim所述):

然而,在Lisp中,函数print在要打印的对象之前加一个换行符,在…之后加一个空格。。。在UNIX中,只有一个合理的策略,因为UNIX解释器(shell)的所有输入都由换行符终止,所以以前不需要换行符。然而,在某些Lisp解释器中,输入可以通过匹配的右括号终止。在这种情况下,需要在前面换行,以免输出与输入出现在同一行上


我只是在猜测,但我想冒昧地说,前导新行只是尾随新行的一个变体(一个标准可以说和另一个标准一样好);后面的空格是因为当第一次编写
print
时,您希望将机械TTY的打印头移开,以便可以看到所写的内容。@Dolda2000在查看CL的前辈并发现原来的
print
只是在Lisp 1.5中输出了一个尾随新行,这似乎不太可能。听起来很合理,这可能是最有用的。如果你手头碰巧有消息来源,那就最好提一下,但我意识到官方原因可能不会在任何地方提及。无论如何,我明天会接受这个答案,除非到时候有更好的答案。引用PAIP:“然而,在Lisp中,
print
函数在要打印的对象前加一个换行符,在对象后加一个空格……在UNIX中,只有一个合理的策略,因为所有输入到UNIX解释器(shell)中是由换行符终止的,因此之前不需要换行符。但是,在某些Lisp解释器中,输入可以由匹配的右括号终止。在这种情况下,需要换行符之前,以免输出与输入出现在同一行。“@jimg:您使用的是Unix终端。我的示例来自LispWorks侦听器窗口,它不是基于终端的。其他Lisp系统也在Lisp控制下读取Lisp表达式。例如,在MIT Lisp机器的REPL中,最后一个右括号也输入表达式