2

我正在使用管道来通信两个 Prolog 进程,每次我到达read/2谓词以从我的管道中读取消息时,程序都会阻塞并保持这种状态。我不明白为什么会发生这种情况(我尝试了非常简单的程序),最后我意识到了三件事:

  1. 每次我write/2用来发送消息时,发送者进程都必须以.\n. 如果消息没有这样结束,接收进程将卡在read/2谓词上。
  2. 如果发送方不刷新输出,则消息不会留在管道缓冲区中。这似乎很明显,但一开始并不适合我。
  3. 虽然当消息没有被刷新时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(假设消息没有被刷新)?

谢谢!

4

1 回答 1

2

有效的 Prolog 读取项总是以句点结尾,称为end char (* 6.4.8 *). 在 6.4.8 其他标记中,标准内容如下:

结束字符后应跟随布局字符或%.

所以这就是标准的要求。

除了空格、制表符和其他布局字符以及%. 然而,由于 ttys 和相关缓冲的流行,坚持使用换行符似乎是一个很好的惯例。

需要 end char 的原因是 Prolog 语法允许中缀和后缀运算符。考虑作为输入

f(1) + g(2).

阅读时f(1)您可能会认为这已经是整个术语,但是您仍然必须等待该期间以确保此后没有中缀或后缀。

另请注意,您必须使用writeq/1orwrite_canonical/1来生成可以回读的输出。你不能使用write/1.

例如,考虑write([(.)+ .]).首先,这是有效的语法。点后面紧跟着其他字符。备注.通常称为末尾的句点,而在 Prolog 文本中称为点。

write/1将其写为[. + .]. 请注意,第一个.现在后面是一个空格。所以当这个文本被读回时,只会[.被读到。

还有很多其他丑陋的例子,比如这个,通常他们不会打你。但是一旦你被击中,你就会被击中......

于 2013-04-03T17:17:16.467 回答