Prolog - Infinite loop when closing SWI-prolog - prolog

I've written the code below in Prolog:
go :- write(">>"), read(X), process(X).
And do various things with process/1.
To catch any unknown commands I've added:
process(Y) :- write("unknown command.\n"), go.
The problem is when exiting SWI-Prolog by closing the window before the normal end of the program, it gets into an infinite loop.
I tried to search for what is SWI-Prolog calling when exiting like that but couldn't find it in order to include it in the code.
Any help on that part or an alternative workaround would be really appreciated.
Thanks in advance!

You need to handle the term end_of_file, too.
After the last Prolog term, that is when only layout or comments are read up to the end of the file or stream, read/1 produces the term end_of_file.
Since (in many current systems) the action to perform when reading past end of file (on standard input) is reset, also subsequent reads will produce this term. And thus your program loops while complaining that that it does not know the command end_of_file.

Related

Prolog - Write out facts and reading a users input

I am quite new to Prolog and have had some trouble understanding it.
I have some facts named 'problem' I wish to first print out these facts to the user and then ask them to input a value, this value is then read and used later.
From my understanding thus far, it would be best to use a forall to print out these facts and then use read to read the value inputted, but I am having some issue implementing this. Here is what I have so far, any explanation would be appreciated
My question: How do I read in the input from the user regarding the problem and apply that into a variable for later use?
tellMeYourProblem:-
forall(problem(P),
writeln(P)),
answer = read(X),
problem('1').
problem('2').
problem('3').
problem('4').
problem('5').
problem('6').
problem('7').
problem('8').
problem('9').
problem('10').
Note: This answer uses SWI-Prolog.
How do I read in the input from the user regarding the problem?
You are doing that already with read(X), however read/1 reads terms (terms end with periods) and you probably want to read characters. If you are using SWI-Prolog take a look at Primitive character I/O for reading characters and Predicates that operate on strings for reading strings.
How do I apply that into a variable for later use?
When doing basic I/O with a user at a text level, a REPL is a good way to start. Adding a REPL is a bit more complicated so I will give you the code.
tellMeYourProblem :-
output_problems,
read_input.
output_problems :-
forall(problem(P),
writeln(P)).
read_input :-
repeat,
read_string(user_input, "\n", "\r\t ", _, Line),
process_input(Line).
process_input(Line) :-
string(Line),
atom_number(Line, N),
integer(N),
do_something_with(Line),
fail.
process_input("quit") :-
write('Finished'), nl,
!, true.
do_something_with(X) :-
writeln(X).
problem('1').
problem('2').
problem('3').
problem('4').
problem('5').
problem('6').
problem('7').
problem('8').
problem('9').
problem('10').
Also with Prolog, the style is to use snake casing so tellMeYourProblem should be tell_me_your_problem.
Normally in Prolog a REPL is done with ->/2, (Read Input till quit statement Prolog) , but I changed this to add more guard statements so that the exit condition would work, e.g.
string(Line),
atom_number(Line, N),
integer(N)
or putting the guard in the head, e.g.
process_input("quit")
When doing I/O to a screen and keyboard, the thought is to use stdIn and stdOut but for the keyboard SWI-Prolog uses user_input instead. See: Input and output
After all of the boiler plate code for the REPL is the next part you seek which is to do something with the input value, in this case just print it out.
do_something_with(X) :-
writeln(X).
The easiest to write out the facts of problem/1,
is to use the builtin listing/[0,1]. This builtin
accepts a so called predicate indicator. You can
write out the facts via:
?- listing(problem/1).
The predicate is supported by many Prolog systems
such as GNU Prolog, etc.. For how to read input see
for example the post by Guy Coder.

Problems with library(lambda), currying and SWI Prolog

So I run into some troubles while (ab?)using
lambda.pl.
I do a "use_module(library(lambda))."
in the first lines of a file that
I consult via ["a.prolog"].
Then I get an "undefined procedure ()/3"
and some gibberish afterwards.
The same happens for any order of use_modules.
It happens whether I load a.prolog via
[...], consult or as a script from the cmdline.
I reduced the script to the currying-example from Rosseta code
https://rosettacode.org/wiki/Currying#Prolog
use_module(library(lambda)).
:- initialization(main, main).
main :-
N = 5, F = \X^Y^(Y is X+N), maplist(F, [1,2,3], L),
print(L).
It doesn't work.
It works, however, if I a manually load 'lambda'
at the swipl-prompt and immeditately consult
a.prolog. Then the goal N=5,.... works just fine.
If I, however, first consult a.prolog; then manually
use_module and then run the query, I get the error.
Reconsulting doesn't help onwards.
Somehow, the first command at the prompt needs to
be use_module.
Or do I get the loading mechanism completely wrong?
If so, please apologize; but I would love get a
hint how to solve this.
This is a common error when first using modules.
Please have a look at this line:
use_module(library(lambda)).
This is just a fact, saying "use_module(library(lambbda)) holds".
What you want instead is a directive.
A directive is a term with primary functor (:-)/1. That is, you want:
:- use_module(library(lambda)).
EDIT: For the particular case of library(lambda), I would like to add that there is a page with a lot of useful information about it that is a bit hard to find:
http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/ISO-Hiord
"Hiord" stands for higher order.

How to turn off "true" and "false" outputs in Prolog?

I would like to write a small text-based adventure game using Prolog (this might be a dumb idea but I am not here to discuss that).
The only problem is that I can't manage to print text on screen without the "true" and "false" values to appear as well.
For instance if I try something like:
take(desk) :- write('This thing is way too heavy for me to carry!').
where take is a one place predicate and desk a name I get as an output:
?- take(desk).
This thing is way too heavy for me to carry!
true.
How can I get rid of this "true" or "false" outputs?
Just to mention that I also tried with the format/1 one place predicate for simple text output and also the format/2 two place predicate (when I want to output the name of a variable) but it gives exactly the same problem.
I have also seen this answer but first it is not detailed enough (at least not for someone like me) and second, I hope deep inside that there is a simpler manner to do it.
And finally, I am using SWI-Prolog.
Thank you.
A simplistic method would be to create a little REPL (read, evaluate, print loop) of your own. Something like this:
game :-
repeat,
write('> '),
read(X),
call(X),
fail.
This will just prompt and execute whatever you enter at the prompt. In conjunction with your take fact (and another I added for illustration):
take(desk) :- write('This thing is way too heavy for me to carry!'), nl.
take(chair) :- write('This is easier to carry.'), nl.
You would get:
?- game.
> take(desk).
This thing is way too heavy for me to carry!
> take(chair).
This is easier to carry.
>
You don't get the true or false because the game goal doesn't resolve until you exit the loop somehow. You could add checks for a quit or bye or whatever to exit the game loop. Ctrl-C or Ctrl-D can be used as well to abort the loop. You might need to add some other "features" to make it work to your needs or liking.

Defining predicates in SICStus Prolog / SWI-Prolog REPL

I am reading http://cs.union.edu/~striegnk/learn-prolog-now/html/node3.html#subsec.l1.kb1,
but I am having trouble running the following predicate:
SICStus 4.0.1 (x86-win32-nt-4): Tue May 15 21:17:49 WEST 2007
| ?- woman(mia).
! Existence error in user:woman/1
! procedure user:woman/1 does not exist
! goal: user:woman(mia)
| ?-
If, on the other hand, I write it to a file and run consult the file, it seems to work fine...
Am I only allowed to define predicates in a file having later to consult them? Can't I just do it in the editor itself?
It's a little annoying to make predicates in the repl. You could do
| ?- ['user'].
woman(mia).
^D
ie consult user input, or
| ?- assertz(woman(mia)).
assert it. Both awkward IMO -- there might be a better way, though, I just don't know it. In general it is easier to use a script.
You should enter woman(mia). into a file to assert it as a fact. If you write it into the interpreter, it's taken as a query, not a fact.
From the SWI Prolog FAQ:
Terms that you enter at the toplevel are processes as queries, while
terms that appear in a file that is loaded into Prolog is processed as
a set of rules and facts. If a text reads as below, this is a rule.
carnivore(X) :- animal(X), eats_meat(X).
Trying to enter this at the toplevel results in the error below. Why?
Because a rule is a term :-(Head, Body), and because the toplevel
interprets terms as queries. There is no predicate with the name :-
and two arguments.
?- carnivore(X) :- animal(X), eats_meat(X). ERROR: Undefined
procedure: (:-)/2 ERROR: Rules must be loaded from a file ERROR:
See FAQ at http://www.swi-prolog.org/FAQ/ToplevelMode.txt
Isn't this stupid? Well, no. Suppose we have a term
eats_meat(rataplan). If this appears in a file, it states the fact
that rataplan eats meat. If it appears at the toplevel, it asks Prolog
to try proving whether rataplan eats meat.
If a text reads
:- use_module(library(clpfd)).
This is a directive. Directives are similar to queries, but instead of
asking the toplevel to do something, they ask the compiler to do
something. Like rules and facts, such terms belong in files.
Instead of writing to a file you can also use assert in the toplevel (as explained later in the FAQ as well).

Undefined Procedure in SWI-Prolog does not work

I am just starting to use Prolog, and already I've run into problem with a seemingly simple example. Here is my .pl file:
hacker(P) :- mountaindew(P), doesntsleep(P).
hacker(P) :- writesgoodcode(P).
writesgoodcode(jeff).
Then, after I load the program into swipl, I test it with this line at the prompt
writesgoodcode(jeff).
I thought it would display true, but I get this error:
?- hacker(jeff).
ERROR: hacker/1: Undefined procedure: mountaindew/1
Exception: (7) hacker(jeff) ?
This program works fine, but this doesn't solve my problems:
hacker(P) :- writesgoodcode(P).
writesgoodcode(jeff).
$ swipl -s dumb.pl
% dumb.pl compiled 0.00 sec, 1,112 bytes
?- hacker(jeff).
true.
Can anyone explain why my original program doesn't work? From my understanding, Prolog should "skip" the first statement since it doesn't have enough information, and check the next line. It does have enough info for that second line, and thus it should evaluate true. Any help or a point in the right direction would be great. Thanks.
As the error message says, you have an undefined procedure mountaindew/1. To make your code return true, your options are:
Define this predicate
Declare that this predicate is dynamic: dynamic(mountaindew/1)
Declare that all unknown predicates should fail (not recommended): set_prolog_flag(unknown, fail)
you could also change the order of the predicates (cannot be done always ofc)
but mostly what Kaarel said.
in the end there is not really a point in writing something that will always fail, even if you are still developing the code
This works but as I am a beginner I can't say why. The word "uninstantiated" may apply. Despite not knowing why it works, I think it's helpful to show one way that works.
hacker(P) :- mountaindew(P), doesntsleep(P).
hacker(P) :- writesgoodcode(P).
mountaindew(john).
doesntsleep(john).
writesgoodcode(jeff).

Resources