I ask SICStus Prolog ?- at_end_of_stream. on the top-level and immediately I get: no.
GNU Prolog and Scryer Prolog do the same.
Traella Prolog and SWI-Prolog, however, choose to wait for input before answering, and rumor has it that behaving like this has been quite common among Prolog systems—especially in the past.
If I look at the ISO-Prolog standard, that behavior becomes spurious:
8.11.8.5 Bootstrapped built-in predicates
The built-in predicatesat_end_of_stream/0andat_the_of_stream/1examine the single stream-propertyend_of_stream/1.A goal
at_end_of_streamis true iff the current input has a stream position end-of-stream or past-end-of-stream (7.10.2.9, 7.10.2.13).A goal
at_end_of_stream(S_or_a)is true iff the stream associated with stream or aliasS_or_ahas a stream position end-of-stream.at_end_of_stream :- current_input(S), stream_property(S, end_of_stream(E)), !, (E = at ; E = past).[The the sake of brevity, I omitted the code for
at_end_of_stream/1.]
So it appears that the standard is quite clearly on the side of SICStus Prolog and GNU Prolog.
So my question boils down to this:
Is this "waiting" behavior simply non-conformance, a kind of anachronism justified on the basis of practicality / compatibility—or is there more to it?
Handling end of stream is hard, on the top-level it's even harder.
A very simple and basic top-level is like
sh(dash). Prolog top-level is a bit similar, it differs by having auto-completion/choice (like Scryer Prolog, SWI-Prolog), not accepting input with ctrl-D but it could be likesh.A query to test and better understand top-level is
?- get_char(C).%a(whereCbinds to%, source) and?- get_char(C).(when submitting with enter,Cbinds to\n, if submitting with ctrl-D then waits or bindsCtoend_of_file).Why those query? The top-level can be model as
read_term(user_input, Goal, []), call(Goal):get_char(C).%asubmitted with enter: The query is parsed and theuser_inputis%a\nthusCbinds to%and ifget_char(C)is replaced byat_end_of_streamthenat_end_of_stream/0fails.get_char(C).submitted with enter: The query is parsed and theuser_inputis\nthusCbinds to\nand ifget_char(C)is replaced byat_end_of_streamthenat_end_of_stream/0fails.get_char(C).submitted with ctrl-D: The query is parsed and theuser_inputis empty. Now the stream position ofuser_inputshould beend-of-streamorpast-end-of-streamifread_term/3is executed as procedurally specified in8.14.1.1:user_inputdoesn't have an end then with the note of7.10.2.9the stream postion can't beend-of-streamorpast-end-of-stream. Is the stream reset and hasend_of_streampropertynot? What happens if the stream doesn't have the propertyeof_action(reset)? In any caseget_char/1waits and ifget_char(C)is replaced byat_end_of_streamthenat_end_of_stream/0fails (there is an opportunity forat_end_of_stream/0to wait here).user_inputhas a size but it's unknown (or variable but still unknown) then:end-of-streamthenCbinds toend_of_fileand ifget_char(C)is replaced byat_end_of_streamthenat_end_of_stream/0succeeds.past-end-of-streamthenget_char/1waits and ifget_char(C)is replaced byat_end_of_streamthenat_end_of_stream/0succeeds.Sadly there is a bit of twisting at the end.
I might have missed/misread something if not then this undefinedness allows some optimization/simplification of the implementation, explains the difference between engine and also the actual top-level is more complicated that
read_term(user_input, Goal, []), call(Goal)(even if it's the ideal one).When it comes to
at_end_of_stream/0, it doesn't seem like there is a reason to wait.Digression
If
at_end_of_stream/0is implemented withpeek_char/1without executingeof_actionthen that might explain the wait.On other operating system, it may be different. I use and test on Linux.
On GNU Prolog (version 1.5.0), there is the issue that a stream with property
eof_action(reset)is never at end of stream. This explains whyat_end_of_stream/0fails.at_end_of_stream/0fails even when the stdin is empty.On Trealla Prolog (version v2.1.11):
The property
end_of_streamdoesn't agree withat_end_of_stream/1(permutingstream_property/2andat_end_of_stream/1doesn't change the result).On Scryer Prolog (on master (6b8e6204957bfc3136ea39ec659d30627775260d) or rebis-dev (c1945caf11c0d202f4121de446f1694854dcba47)):
at_end_of_stream/0fails even when the stdin is empty.