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

时间:2017-02-16 02:16:53

标签: lisp common-lisp

The Common Lisp Hyperspec page for print提及:

  

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

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

我正在寻找原因。我知道这可能仅仅是因为那是另一种常见的lisp可能会如何做到这一点,而普通lisp只是采用它,但如果是这样的话,我正在寻找其他中的设计理由口齿不清。

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

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

编辑:

我研究了Common-Lisp的前辈,特别是InterLisp,MacLisp和MacLisp的前身Lisp 1.5。

Interlisp(this pdf中的第145页)和Lisp 1.5(this pdf中的第140页)print函数打印对象后跟换行符。

似乎MacLisp引入了这种差异。我在原始参考手册中没有找到原因,我只找到了以下on this revised reference manual

  

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

当然,原始定义中的尾随换行符就足够了,所以这个原因似乎不合适。

编辑2:

如Rainer Joswig所说,似乎这一变化出现在MacLisp之前的Lisp 1.6中。

2 个答案:

答案 0 :(得分:5)

例如参见:PDP-6 LISP (LISP 1.6) Revised. (January 1967)

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

Jon L White会知道的。

请参阅第1页上的REPL示例,读取eval PRINT循环。 在这里,我使用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 

每个结果都是独立的。这是顺便说一句。也喜欢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

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

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

  

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

答案 1 :(得分:2)

基本上这是一个仅限REPL的功能,类似于“穷人”tracedebug"

它的用例类似于

(map nil #'print list)

或者更一般地说,

(complex-traversal-map #'print weird-structure)

在打印对象周围插入空白以避免干扰 与其他print调用的输出。 几十年来,发出了什么样的空白。 它应该被称为print-on-a-separate-line但它必须是。post.component.ts 简短易猜。

它本质上是"遗产"功能,如rplaca and rplacd