سؤال

I'm using pipes to communicate two Prolog processes and every time I reached a read/2 predicate to read a message from my pipe, the program blocked and remained like that. I couldn't understand why that happened (I tried with extremely simple programs) and at the end I realized three things:

  1. Every time I use write/2 to send a message, the sender process must end that message with .\n. If the message does not end like this, the receiver process will get stuck at the read/2 predicate.
  2. If the sender does not flush the output, the message therefore is not left in the pipe buffer. It may seem obvious but it wasn't for me at the beginning.
  3. Although when the message is not flushed the read/2 is blocking, wait_for_input/3 is not blocking at all, so no need for flush_output/1 in such case.

Examples:

This does not work:

example1 :-
    pipe(R,W),
    write(W,hello),
    read(R,S). % The program is blocked here.

That one won't work either:

example2 :-
    pipe(R,W),
    write(W,'hello.\n'), 
    read(R,S). % The program is blocked here.

While these two, do work:

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).

Now my question is why? Is there a reason why Prolog only "accepts" full lines ended with a period when reading from a pipe (actually reading from any stream you may want to read)? And why does read block while wait_for_input/3 doesn't (assuming the message is not flushed)?

Thanks!

هل كانت مفيدة؟

المحلول

A valid Prolog read-term always ends with a period, called end char (* 6.4.8 *). And in 6.4.8 Other tokens, the standard reads:

An end char shall be followed by a layout character or a %.

So this is what the standard demands.

A newline after the period is one possibility to end a read-term, besides space, tab and other layout characters as well as %. However, due to the prevalence of ttys and related buffering, it seems a good convention to just stick with a newline.

The reason why the end char is needed is that Prolog syntax permits infix and postfix operators. Consider as input

f(1) + g(2).

when reading f(1) you might believe that this is already the entire term, but you still must await the period to be sure that there is no infix or postfix thereafter.

Also note that you must use writeq/1 or write_canonical/1 to produce output that can be read back. You cannot use write/1.

As an example, consider write([(.)+ .]). First, this is valid syntax. The dots are immediately followed by some other character. Remark the . is commonly called a period at the end, whereas it is called a dot within Prolog text.

write/1 will write this as [. + .]. Note, that the first . is now followed by a space. So when this text is read back, only [. will be read.

There are many other ugly examples such as this one, usually they do not hit you. But once you are hit, you are hit...

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top