How to turn off "true" and "false" outputs in Prolog? - 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.

Related

Prolog - Infinite loop when closing SWI-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.

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.

Prolog Cut operator

I defined my knowledge base as:
edge(mammal,isa,animal).
edge(human,isa,mammal).
edge(simba,isa,human).
edge(animal,swim,bybirth).
edge(human,swim,mustlearn).
path(X,Y) :- edge(X,isa,Y).
path(X,Y) :- edge(X,isa,Z), path(Z,Y).
swim(X,Y) :- edge(X,swim,Y).
swim(X,Y) :- path(X,Z), swim(Z,Y).
Now, to use the above knowledge base, I use the following:
?- swim(simba,bybirth).
?- swim(simba,mustlearn).
And for both the queries, Prolog returns true. I want Prolog to check for the property swim locally first, then look at the direct parent, and so on in a hierarchical fashion. And it should stop searching as soon as we know that Simba "mustlearn" to swim, and shouldn't look any further. Thus, it should return false for the first query and true for the second.
I know it has to be done by limiting backtracking. I tried using the cut and not operators, but couldn't succeed. Is there a way to achieve this?
I tried it and ran into a problem too. I thought this might work:
swim(X,Y) :- once((edge(X,swim,Y); path(X,Z), swim(Z,Y))).
It doesn't work, because if Y is already instantiated on the way in, the first step will fail to unify and it will try the second route going through the human intermediate. So even though the query only produces one result, it can be fooled into producing swim(simba, bybirth). The solution is to force Prolog to commit to a binding on another variable and then check that binding after the commitment:
swim(X,Y) :-
once((edge(X,swim,Method); path(X,Z), swim(Z,Method))),
Method = Y.
This tells Prolog, there is only one way to get to this method, so find that method, and then it must be Y. If you find the wrong method, it won't go on a search, it will just fail. Try it!

Prolog Relational Tracking without Lists

I am trying to get a predicate to relate from 1 fact to another fact and to keep going until a specified stopping point.
For example,
let's say I am doing a logistics record where I want to know who got a package from who, and where did they get it from until the end.
Prolog Code
mailRoom(m).
gotFrom(annie,brock).
gotFrom(brock,cara).
gotFrom(cara,daniel).
gotFrom(daniel,m).
gotFrom(X,Y) :- gotFrom(Y,_).
So what I am trying to do with the predicate gotFrom is for it to recursively go down the list from what ever point you start (ex: gotFrom(brock,Who)) and get to the end which is specified by m, which is the mail room.
Unfortunately when I run this predicate, it reads out,
Who = annie.
Who = brock.
Who = cara.
etc.etc....
I tried stepping through the whole thing but Im not sure where it goes from brock to annie, to cara and all the way down till it cycles through trues for infinity. I have a feeling that it has something to do with the wildcard in the function (_), but Im not sure how else I could express that part of the function in order for the predicate to search for the next fact in the program instead of skipping to the end.
I tried using a backcut (!) in my program but it gives me the same error.
Any help is greatly appreciated. I don't want code I just want to know what I am doing wrong so I can learn how to do it right.
Thanks.
I'm afraid this rule is meaningless:
gotFrom(X,Y) :- gotFrom(Y,_).
There is nothing here to constrain X or Y to any particular values. Also, the presence of singleton variable X and the anonymous variable _ means that basically anything will work. Try it:
?- gotFrom([1,2,3], dogbert).
true ;
true ;
What I think you're trying to establish here is some kind of transitive property. In that case, what you want is probably more like this:
gotFrom(X,Z) :- gotFrom(X, Y), gotFrom(Y, Z).
This produces an interesting result:
?- gotFrom(brock, Who).
Who = cara ;
Who = daniel ;
Who = m ;
ERROR: Out of local stack
The reason for the problem may not be immediately obvious. It's that there is unchecked recursion happening twice in that rule. We recursively unify gotFrom/2 and then we recursively unify it again. It would be better to break this into two predicates so that one of them can be used non-recursively.
got_directly_from(annie,brock).
got_directly_from(brock,cara).
got_directly_from(cara,daniel).
got_directly_from(daniel,m).
gotFrom(X,Y) :- got_directly_from(X, Y).
gotFrom(X,Z) :- got_directly_from(X, Y), gotFrom(Y, Z).
This gives us the desired behavior:
?- gotFrom(brock, Who).
Who = cara ;
Who = daniel ;
Who = m ;
false.
Notice this one is resilient to my attack of meaningless data:
?- gotFrom([1,2,3], dogbert).
false.
Some general advice:
Never ignore singleton variable warnings. They are almost always a bug.
Never introduce a cut when you don't understand what's going on. The cut should be used only where you understand the behavior first and you understand how the cut will affect it. Ideally, you should try to restrict yourself to green cuts—cuts that only affect performance and have no observable effects. If you don't understand what Prolog is up to, adding a red cut is just going to make your problems more complex.

how can I print all database facts in prolog

I have a database in prolog, all I want to do is enuamrate through its element and print one by one. How can this be done?
fact(is(mike,asthmatic)).
fact(has(andy,highPressure)).
fact(is(mike,smoker)).
I have written this, which works ok but it removes elements from the database, so I want to access them without removing.
print:-
retract(factA(P)),
write(factA(P)),nl,
fail.
print.
You might also consider using forall/2 predicate:
print:-
forall(fact(P), writeln(P)).
Well, you were almost there :
print :-
fact(A),
writeln(A),
First, we get a fact and print it.
fail;true.
Then, we backtrack (through fail) until no solution is left. To avoid returning false, we add the disjunction with true.
Note that you can proceed differently, like :
print2 :-
findall(Fact, fact(Fact), Facts),
maplist(writeln, Facts).
But if you go that road, prefer #gusbro solution, it's better !

Resources