at_end_of_stream on stdin in Prolog - prolog

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 predicates at_end_of_stream/0 and at_the_of_stream/1 examine the single stream-property end_of_stream/1.
A goal at_end_of_stream is 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 alias S_or_a has 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 like sh.
A query to test and better understand top-level is ?- get_char(C).%a (where C binds to %, source) and ?- get_char(C). (when submitting with enter, C binds to \n, if submitting with ctrl-D then waits or binds C to end_of_file).
Why those query?
The top-level can be model as read_term(user_input, Goal, []), call(Goal):
Case get_char(C).%a submitted with enter: The query is parsed and the user_input is %a\n thus C binds to % and if get_char(C) is replaced by at_end_of_stream then at_end_of_stream/0 fails.
Case get_char(C). submitted with enter: The query is parsed and the user_input is \n thus C binds to \n and if get_char(C) is replaced by at_end_of_stream then at_end_of_stream/0 fails.
Case get_char(C). submitted with ctrl-D: The query is parsed and the user_input is empty. Now the stream position of user_input should be end-of-stream or past-end-of-stream if read_term/3 is executed as procedurally specified in 8.14.1.1:
If user_input doesn't have an end then with the note of 7.10.2.9 the stream postion can't be end-of-stream or past-end-of-stream. Is the stream reset and has end_of_stream property not? What happens if the stream doesn't have the property eof_action(reset)? In any case get_char/1 waits and if get_char(C) is replaced by at_end_of_stream then at_end_of_stream/0 fails (there is an opportunity for at_end_of_stream/0 to wait here).
Else user_input has a size but it's unknown (or variable but still unknown) then:
If stream position is end-of-stream then C binds to end_of_file and if get_char(C) is replaced by at_end_of_stream then at_end_of_stream/0 succeeds.
Else stream position is past-end-of-stream then get_char/1 waits and if get_char(C) is replaced by at_end_of_stream then at_end_of_stream/0 succeeds.
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/0 is implemented with peek_char/1 without executing eof_action then 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 why at_end_of_stream/0 fails.
$ echo -n | gprolog --init-goal "(at_end_of_stream, write(at), nl, halt ; peek_char(C), writeq(not(C)), nl, halt)"
not(end_of_file)
$ echo | gprolog --init-goal "(at_end_of_stream, writeq(at), nl, halt ; peek_char(C), writeq(not(C)), nl, halt)"
not('\n')
at_end_of_stream/0 fails even when the stdin is empty.
On Trealla Prolog (version v2.1.11):
$ echo -n | ./tpl -g "(at_end_of_stream, writeq(at), nl, halt ; peek_char(C), writeq(not(C)), nl, halt)"
at
$ echo | ./tpl -g "(at_end_of_stream, writeq(at), nl, halt ; peek_char(C), writeq(not(C)), nl, halt)"
not('\n')
$ echo -n | ./tpl -g "(stream_property(S, alias(user_input)), stream_property(S, end_of_stream(Eos)), at_end_of_stream(S), writeq(eos(Eos)), halt ; halt)"
eos(not)
The property end_of_stream doesn't agree with at_end_of_stream/1 (permuting stream_property/2 and at_end_of_stream/1 doesn't change the result).
On Scryer Prolog (on master (6b8e6204957bfc3136ea39ec659d30627775260d) or rebis-dev (c1945caf11c0d202f4121de446f1694854dcba47)):
$ echo -n | ./target/release/scryer-prolog -g "(at_end_of_stream, write(at), nl, halt ; peek_char(C), writeq(not(C)), nl, halt)"
not('\x0\')
$ echo | ./target/release/scryer-prolog -g "(at_end_of_stream, write(at), nl, halt ; peek_char(C), writeq(not(C)), nl, halt)"
not('\n')
at_end_of_stream/0 fails even when the stdin is empty.

How to make the at_end_of_stream/0/stream_property/2 wait?
Using the top-level read_term(user_input, Goal, []), call(Goal), the query ?- get_char(C), at_end_of_stream. can wait.
The query ?- at_end_of_stream. doesn't wait because of read_term/3 since it needs to peek to determine the end token and it can update the stream position.
If user_input doesn't have an end then with the note of 7.10.2.9, at_end_of_stream/0 fails.
Else user_input has a size but it's unknown (or variable but still unknown) then at_end_stream/0 waits. The query get_char(C), at_end_of_stream. is submitted with enter. The query is parsed and user_input is \n. Now get_char/1 reads \n, user_input is empty and get_char/1 should update stream position as specified by 8.12.1.1. But get_char/1 can't update user_input and needs not do an update by peeking, it can be left for when the user tries to observe with at_end_of_stream/0. Now at_end_of_stream/0 waits.
Another way to make at_end_of_stream/0 waits is to use the top-level at_end_of_stream. The initial stream position of user_input is unknown (the size of the stream is unknown) thus at_end_of_stream/0 waits.
Small digression: get_char/1 can't update the stream position of user_input unless it reads end_of_file in which case user_input stream position is updated to past-end-of-stream.

Related

Prolog : Never Ending Process

I am trying to use get_coeff_value() but the process never end.
get_coeff_value(Val,[],[]).
get_coeff_value(Val, [X|T],Coeff_List):-
get_coeff_value(Val,T,Coeff_List1),
get_val(Val,[X], Coeff),
insert_end(Coeff_List1, Coeff, Coeff_List).
command : get_coeff_value('H', ['H'-5, 'C'-2], Coeff).
I tried get_val() and insert_end() both end perfectly.
However this one display :
command result
It gives me the answer I am waiting for but it never stops the process.
This looks the same as what happens if you query e.g. ?- member(X, [1,2,3]). ; your code has left choicepoints and the Prolog toplevel has found one solution but has not explored the whole search space of your code, so it is waiting for your input.
Press ? to see the help, ; or space to continue searching for more answers, or a to abort the search and stop there.
SWI Prolog help on pressing ?
Possible actions:
; (n,r,space,TAB): redo | t: trace&redo
*: show choicepoint | c (a,RET): stop
w: write | p: print
b: break | h (?): help

How to run prolog queries from within the prolog file in swi-prolog?

If I have a prolog file defining the rules, and open it in a prolog terminal in windows, it loads the facts. However, then it shows the ?- prompt for me to manually type something. How can I add code to the file, so that it will actually evaluate those specific statements as if I typed them in?
something like this
dog.pl
dog(john).
dog(ben).
% execute this and output this right away when I open it in the console
dog(X).
Does anyone know how to do this?
Thanks
There is an ISO directive on this purpose (and more): initialization
If you have a file, say dog.pl in a folder, with this content
dog(john).
dog(ben).
:- initialization forall(dog(X), writeln(X)).
when you consult the file you get
?- [dog].
john
ben
true.
Note that just asserting dog(X). doesn't call dog(X) as a query, but rather attempts to assert is as a fact or rule, which it will do and warn about a singleton variable.
Here's a way to cause the execution the way you're describing (this works for SWI Prolog, but not GNU Prolog):
foo.pl contents:
dog(john).
dog(ben).
% execute this and output this right away when I open it in the console
% This will write each successful query for dog(X)
:- forall(dog(X), (write(X), nl)).
What this does is write out the result of the dog(X) query, and then force a backtrack, via the false call, back to dog(X) which will find the next solution. This continues until there are no more dog(X) solutions which ultimately fails. The ; true ensures that true is called when dog(X) finally fails so that the entire expression succeeds after writing out all of the successful queries to dog(X).
?- [foo].
john
ben
true.
You could also encapsulate it in a predicate:
start_up :-
forall(dog(X), (write(X), nl)).
% execute this and output this right away when I open it in the console
:- start_up.
If you want to run the query and then exit, you can remove the :- start_up. from the file and run it from the command line:
$ swipl -l foo.pl -t start_up
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.2.3)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.
For help, use ?- help(Topic). or ?- apropos(Word).
john
ben
% halt
$
dog.pl:
dog(john).
dog(ben).
run :- dog(X), write(X).
% OR:
% :- dog(X), write(X).
% To print only the first option automatically after consulting.
Then:
$ swipl
1 ?- [dog].
% dog compiled 0.00 sec, 4 clauses
true.
2 ?- run.
john
true ; # ';' is pressed by the user
ben
true.
3 ?-

Prolog, getting right answer in terminal, but wrong answer when running a program

Typing "prolog" in terminal gets:
GNU Prolog 1.3.0
By Daniel Diaz
Copyright (C) 1999-2007 Daniel Diaz
| ?-
Typing:
| ?- member(2, [1,2,3]).
Gets:
true ?
Then pressing enter gets:
yes
Typing:
| ?- member(4, [1,2,3]).
gets:
no
When i write a file; test.pl consisting of this:
:- member(4, [1,2,3]), nl, halt.
And then write in the terminal:
| ?- [test2].
I get:
compiling /path/test.pl for byte code...
/path/test.pl:1: warning: unknown directive (',')/2 - maybe use initialization/1 - directive ignored
/path/test.pl compiled, 1 lines read - 139 bytes written, 11 ms
yes
Shouldnt the answer here be no? What am i doing wrong. Also, how would you do this in prolog:
if (testInPrologTerminal(member(4, [1,2,3])) { do this; }
I.e, i want to send queries to the prolog top level, and get an answer
When you type the query member(2, [1,2,3]), GNU Prolog prompts you for a possible additional solution (hence the true ? prompt) as only by backtracking (and looking to the last element in the list, 3) it could check for it. When you press enter, you're telling the top-level interpreter that you are satisfied with the current solution (the element 2 in the list second position). The second query, member(4, [1,2,3]), have no solutions so you get a no.
To execute a query when a file is loaded, the standard and portable way of doing it, is to use the standard initialization/1 directive. In this case, you would write:
:- initialization((member(4, [1,2,3]), nl, halt)).
Note the ()'s surrounding the query, otherwise you may get a warning about an unknown initialization/3 standard, built-in, control construct. If you have more complex queries to be executed when a file is loaded, then define a predicate that makes the queries a call this predicate from the initialization/1 directive. For example:
main :-
( member(4, [1,2,3]) ->
write('Query succeeded!'), nl
; write('Query failed!'), nl
).
:- initialization(main).
Writing arbitrary queries as directives in a source file is legacy practice and thus accepted by several Prolog implementations but using the initialization/1 directive is the more clean, standard, and portable alternative.

Writing recursion in swi-prolog

I have successfully connected PHP with Prolog and managed to query the desired knowledge base that resides in knowledge_base.pl file and managed to echo the results via php exec function.
I encountered a problem in echoing the true/false value that Prolog returns after each query execution (see previous question) so I came up with a solution that I have trouble implementing.
Let's assume I have a simple knowledge_base.pl file with these facts and rules:
girl(erin).
boy(john).
likes(erin, reading).
likes(john, reading).
hangs_out_with(erin, X) :-
likes(X, reading),
boy(X),
writeln('Someone s got a new friend!!').
Lets say that I want to see if erin is a girl and if so, write that it is true, or else write that it is false. I added this to my knowledge_base.pl file:
girl(erin) :-
girl(erin)
-> write('it is true')
; write('it is not true').
When I enter the query: ?- girl(erin). I get an out of local stack error. I searched the Web and found out that this is due to infinite recursion.
Can someone give me a hint in how to write
girl(X) :-
( girl(X)
-> write('it is true')
; write('it is not true')).
in Prolog? Thanks in advance.
As a new user I'm not allowed to post pictures.
SWI-Prolog's output:
1 ?-hangs_out_with(erin,kosta).
false.
2 ?-hangs_out_with(erin,john).
Someone s got a new friend!!
true.
Command prompt's output:
C:\(directory)>swipl -q -f knowledge_database.pl -g hangs_out_with(erin,kosta),halt.
1 ?-halt. (the halt is inputted by me.)
C:\(directory)>swipl -q -f knowledge_database.pl -g hangs_out_with(erin,john),halt.
Someone s got a new friend!!
The first query fails and the second succeds. As you can see, prolog after the query executions outputs true/false but when i execute the same query in command prompt the true/false values do not get echoed!!
I think you should ask
is_girl(X) :-
girl(X) -> write('t is true') ; write('it is not true').
EDIT
Do you mean this kind of thing ?
is_type(Type, X) :-
call(Type, X) -> writeln(yes); writeln(no).
so you "connect PHP to Prolog" by executing a Prolog query in command shell and capturing and analyzing its output. http://www.swi-prolog.org/man/quickstart.html says
"2.1.1.1 Starting SWI-Prolog on Unix
By default, SWI-Prolog is installed as 'swipl'. The command-line arguments of SWI-Prolog itself and its utility programs are documented using standard Unix man pages."
So do consult a man page about "-q" switch. Is it the "-q" for quiet perhaps? What does "-f" mean (ok, that's probably "file")? But the solution is the same - just use a different name for the new predicate.
Notice that in your first attempt,
C:>swipl -q -f knowledge_database.pl -g hangs_out_with(erin,kosta),halt.
1 ?-halt. (the halt is inputted by me.)
halt isn't executed, precisely because hangs_out_with(erin,kosta) has failed. A comma signifies conjunction (an "and").
All you need to do is create a new predicate that reports whether the goal is true or false, and succeeds always:
report_hangs_out_with(A,B):-
hangs_out_with(A,B)- > writeln(['YES',A,B]) ; writeln('NO').
and use it instead:
C:>swipl -q -f knowledge_database.pl -g report_hangs_out_with(erin,kosta),halt.
Also, Prolog echoing "true" or "false" is part of its interactive session. But you terminate it with halt!
edit: you posted:
1 ?-hangs_out_with(erin,kosta).
false.
So, when you run that query in interactive Prolog shell, it reports the failure. halt/0 exits the Prolog shell. When you run it with a goal specified through command line switch, apparently it does not report the success of failure. That's the fact of nature as far as we users are concerned (a.o.t. the compiler writers). It is easily addressable with what I've shown you. And you yourself say that it works, too. For each predicate that can fail or succeed, define another, reporting predicate, just as I've shown you.
Here's a sample transcript (in Windows, but that's irrelevant). That should clear up your doubts:
C:\Program Files\pl\bin>plcon -q -g (writeln('****'),halt).
**** // didn't say Yes, right??
C:\Program Files\pl\bin>plcon -q
1 ?- writeln('****'),halt.
**** // didn't say Yes here either
C:\Program Files\pl\bin>plcon -q
1 ?- writeln('****').
****
Yes // does say Yes as part of interaction
2 ?- halt.
C:\Program Files\pl\bin>
So that's the way it is. Deal with it. :) Or write Jan and ask him to change it. :)
girl(erin) :-
girl(erin)
-> write('it is true')
; write('it is not true').
This is wrong for two reasons. Prolog tries to resolve the body taking the left-most literal.
So it basically goes in a loop "is erin girl? yes, if erin is girl. Is erin girl?..."
The second reason is you are mixing two different things. Try to keep your knowledge representation part separated from the way you use it.
In Prolog you just say:
girl(erin)
And then query
?- girl(erin)
Prolog will just say "yes". If you want to print it, probably the easiest way is adding a predicate.
check_and_print(X) :- X, write(X), write(" is true").
Probably you need a call(X) instead of X, depending on the implementation you are using.
I'm not sure about the command prompt out, I suspect the outcome is returned in a different way.

How do I show the results of pattern-matching goals with several free variables in SWI-Prolog from a shell invocation?

Let's use the following prolog base :
father(anakinSkywalker, princessLeia).
father(anakinSkywalker, lukeSkywalker).
saysOhNo(lukeSkywalker).
sdesciencelover asked how to show the results of pattern-matching goals in swi-prolog from a shell invocation, and got an answer giving a manual transformation on the query, to isue a write.
swipl -q -s kb.pl -t "father(anakinSkywalker,X), writeln(X), false"
Result:
princessLeia
lukeSkywalker
This works fine when one only has a few queries with a single free variable, but manually transforming each one becomes tedious, and if we want proper output with the name of each variable along with its result, it soon becomes very annoying. For example to run the query father(AVariable, Another), one needs to write:
swipl -q -s kb.pl -t "father(AVariable,Another), write('AVariable='), write(AVariable), write(', Another='), writeln(Another), false"
Result:
AVariable=anakinSkywalker, Another=princessLeia
AVariable=anakinSkywalker, Another=lukeSkywalker
I tried to feed it the commands from a pipe, but it doesn't work great (I can't detect when it has finished writing the results, so it just hangs afterwards, and no newline separates the answers) :
(echo "father(X,Y)."; while true; do echo ";"; done) | swipl -q -s kb.pl
Result :
X = anakinSkywalker,
Y = princessLeia X = anakinSkywalker,
Y = lukeSkywalker.
swipl hangs here, and needs to be stopped with Control-C.
I know I could use a sed script to pre-process queries, adding the necessary code to print the variables in capital letters, but it would need a fair amount of work to work on complex queries, for example where two predicates must be satisfied :
father(X,Y), saysOhNo(Y).
To always give correct results, one would need to write a parser for prolog, which would be useless work since prolog already know how to do this interactively.
So here's my question : is there a way to tell GNU prolog or SWI prolog (or any other free version that can be easily installed on linux) to run some queries and print the results, just like they would do interactively, but without requiring me to type (or copy-paste) each query by hand ?
Edit : a way to store a series of queries in a file (either in the kb.pl file or an auxiliary file) and run them all, showing their results would be even better.
So far, here are the methods I found :
In gprolog
Using false's answer, I found that one must add a line at the top of the kb.pl file:
a(_) :- fail.
and then use ./query.sh kb.pl "father(X,Y), saysOhNo(Y)", where query.sh is:
#!/bin/sh
echo "a(fail)." | gprolog --query-goal "consult('$1'), $2"
When the query returns immediately (i.e. no results or a single result and gprolog managed to detect it was the last one), this will run the query consult('kb.pl'), actual_query., and then run the query a(fail). which will simply print an extraneous no on the console, thanks to the always-false predicate we added at the top of the file.
When gprolog asks what to do (i.e. several results, or a single result and gprolog couldn't detect it was the last one), this will run the query consult('kb.pl'), actual_query., read the a which asks gprolog to print all results, and then it will run the query (fail). which will simply print an extraneous no on the console, because these are just grouping parenthesis, so the query is equivalent to fail..
In xsb
One can use ./query.sh kb.pl "father(X,Y), saysOhNo(Y)", where query.sh is:
#!/bin/sh
(echo "consult('$1'), ${2%.}."; yes halt.) | xsb --noprompt --quietload --nobanner
When xsb asks what to do next, if the user types a non-empty string, followed by enter, it will print the next result, otherwise it will stop searching solutions to the current query. Therefore, with the yes halt. command, we type an infinite stream of non-empty lines. xsb will print all results to the query (each time reading halt., so as it is a non-empty string, it will continue with the next result), and return to its prompt. Then, the following halt. it receives will tell it to quit.
In swi-prolog
I haven't found a solution yet.
[rant]All this would be so much simpler, if the people building prolog implementations actually thought about using them non-interactively, like it's possible with most other languages.[/rant]
You can use the command-line option --query-goal in GNU. Like so:
$ echo a| gprolog --query-goal 'X = 1 ; X =2'
GNU Prolog 1.4.1
By Daniel Diaz
Copyright (C) 1999-2012 Daniel Diaz
| ?- X = 1 ; X =2.
X = 1 ? a
X = 2
yes
You may have found a solution for your problem but anyway, here goes my approach. You can always recurse to the bagof built-in predicate. You may read what it does in the docs, this way you will learn more about it.
swipl -q -s starwars.pl -t "bagof(X, Y^father(X,Y), BagOfFathers), bagof(Y, X^father(X,Y), BagOfChildren), writeln(BagOfFathers), writeln(BagOfChildren)."
[anakinSkywalker,anakinSkywalker]
[princessLeia,lukeSkywalker]
You can also process it later as a mapping or whatever you want, the relations are 1:1 (No sure if is the correct way of stating it but I hope you get it)
you can use the following bash script for swi-prolog:
#!/bin/sh
exec swipl -q -f none -g "load_files([interface],[silent(true)])" \
-t interface:get_args -- $*
this will load the file interface.pl and call the predicate get_args/0
to get the command line arguments you can call:
current_prolog_flag(argv, Arguments)
of course you can change the names of the predicates/files loaded.
the silent(true) arguments suppresses informational messages such as the intro text
edit:
the error message you get is cause you probably dont have an interface.pl file (neither a get_args/0 predicate).
you will have to replace interface with kb (or however you name the file) and interface:get_args with kb:father(X,Y), saysOhNo(Y) or use an auxiliary predicate within your prolog file such as run(X,Y):- father(X,Y), saysOhNo(Y) (which may be kinda cleaner)

Resources