我正在使用管道来通信两个 Prolog 进程,每次我到达 read/2
谓词以从管道读取消息时,程序都会被阻塞并保持这种状态。我无法理解为什么会发生这种情况(我尝试了非常简单的程序),最后我意识到三件事:
- 每次我使用
write/2
发送消息时,发送方进程必须以.\n
结束该消息。如果消息没有这样结束,接收进程将卡在read/2
谓词处。 - 如果发送方不刷新输出,则消息不会留在管道缓冲区中。这似乎是显而易见的,但一开始并不适合我。
- 尽管当消息未刷新时,
read/2
会阻塞,但wait_for_input/3
根本不会阻塞,因此不需要flush_output/1
在这种情况下。
示例:
这不起作用:
example1 :-
pipe(R,W),
write(W,hello),
read(R,S). % The program is blocked here.
那个也行不通:
example2 :-
pipe(R,W),
write(W,'hello.\n'),
read(R,S). % The program is blocked here.
同时这两个,做工作:
example3 :-
pipe(R,W),
write(W,'hello.\n'),
flush_output(W),
read(R,S).
example4 :-
pipe(R,W),
write(W,'hello.\n'),
wait_for_input([W],L,infinite).
现在我的问题是为什么?从管道读取时(实际上是从您可能想要读取的任何流中读取),Prolog 仅“接受”以句点结尾的整行是否有原因?为什么 read
会阻塞,而 wait_for_input/3
不会(假设消息未刷新)?
谢谢!
最佳答案
有效的 Prolog 读取术语始终以句点结束,称为 end char (* 6.4.8 *)
。在 6.4.8 其他标记中,标准如下:
An end char shall be followed by a layout character or a
%
.
这就是标准的要求。
除了空格、制表符和其他布局字符以及 %
之外,句号后面的换行符也是结束读取术语的一种可能。然而,由于 tty 和相关缓冲的盛行,坚持使用换行符似乎是一个很好的约定。
需要结束字符的原因是 Prolog 语法允许中缀和后缀运算符。考虑作为输入
f(1) + g(2).
当阅读 f(1)
时,您可能会认为这已经是整个术语,但您仍然必须等待句点以确保其后没有中缀或后缀。
另请注意,您必须使用 writeq/1
或 write_canonical/1
来生成可读回的输出。您不能使用write/1
。
作为示例,请考虑 write([(.)+ .])。
首先,这是有效的语法。这些点后面紧跟着一些其他字符。请注意 .
通常称为末尾的句点,而在 Prolog 文本中则称为点。
write/1
会将其写为 [。 + .]
。请注意,第一个 .
现在后面跟着一个空格。所以当这段文字被读回来时
仅读取[.
。
还有很多其他丑陋的例子,比如这个,通常它们不会打到你。但一旦你被击中,你就会被击中......
关于stream - 在Prolog中读取流时是否总是需要使用 '.\n'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15793632/