奇怪的普通口齿不清SBCL*查询io*行为



目前正在学习SBCL的Common Lisp,它一直在困扰我查询io与标准输入和输出有一些意想不到的差异。我假设标准输出包含一个换行符,或者用换行符格式化,因为

(format *query-io* "hello")

根本不包含换行符。

现在,使用read行给我这个行为

(defun read (prompt)
(format *query-io* "~a: " prompt)
(read-line))
(read "message")
> hello
"hello"
message: NIL

我被告知这是意料之中的事,因为SBCL会在打印格式之前等待输入新行,但我没有得到的是更改第二行的结果

(defun read (prompt)
(format *standard-output* "~a: " prompt)
(read-line))
(read "message")
> hello
message: 
"hello"
NIL

为什么顺序不同?我不认为提示变量后面的换行符会影响的结果

如果你想让事情以可预测的方式进行,你应该编写程序来确保:

  • 不要将函数命名为read(事实上,我非常确信SBCL不会允许您将函数命名成read,除非您使用的是史前版本)
  • 要清楚你实际阅读和写作的方向
  • 如果您希望输出在给定的时间出现,请说您愿意

所以在你的第一个函数中,你正在做一些与我假设的等价的事情:

(defun f1 (prompt)
(format *query-io* "~a: " prompt)
(read-line))

此:

  1. 将提示写入*query-io*,这意味着在未来的某个时间,它可能出现在*query-io*指向的任何位置
  2. 从CCD_ 6读取一行
  3. 返回读取该行的结果

因此,如果您调用此函数,它将从*standard-input*读取一行,该行可能是终端,但可能不是。在调用format之后的某个时间,*query-io*上可能会出现一些输出,也可能指向终端。如果,则不能保证输出何时出现,甚至不能保证:例如,如果您将函数修改为:

(defun f1.1 (prompt)
(format *query-io* "~a: " prompt)
(clear-output *query-io*)
(read-line))

提示很可能永远不会出现。

如果你没有明确地说"现在就写",那么写入流的函数何时实际出现输出取决于很多因素:

  • 流指向什么
  • 如果有缓冲区
  • 缓冲区有多大
  • 缓冲区有多满
  • 你后来是否在流上调用了clear-output,以及clear-output是否真的做了什么
  • 是否后来用:abort t关闭了流,以及是否真的做了什么
  • 木星卫星上巧克力的价格

在你的第二个函数中,事情基本上是一样的:

(defun f2 (prompt)
(format *standard-output* "~a: " prompt)
(read-line))

这一次format正在写入*standard-output*,而不是*query-io*,并且您再次从*standard-input*读取一行。同样,format的输出何时以及是否出现,取决于神。

所以你需要做的是

  • 要清楚您正在使用的流
  • 实际上,要求输出在您需要的时候出现,而不是稍后出现

特别是永远不要假设写入某个流的输出出现在任何给定点"单独"或"换行后",或类似的情况。

如果你想提示和阅读*query-io*,你可以这样做:

(defun f3 (prompt)
(format *query-io* "~a: " prompt)
(finish-output *query-io*)
(read-line *query-io*))

如果您想在*standard-output*上提示并从*standard-input*读取,则:

(defun f4 (prompt)
(format *standard-output* "~a: " prompt)
(finish-output *standard-output*)
(read-line *standard-input*))

在最后一种情况下,您实际上可以忽略流(并使用t表示format),因为它们是默认值:但显式可能更好。

f3可能更好,因为提示和阅读是*query-io*的作用。

相关内容

  • 没有找到相关文章

最新更新