Why does SWI-Prolog only give me the first answer? - prolog

I'm new to Prolog. I'm just trying simple examples to learn. I have this .pl file with these lines:
parent(pam,bob).
parent(tom,bob).
parent(tom,lio).
parent(bob,ann).
parent(bob,pat).
parent(pat,jim).
After consulting and testing, it only shows the first answer. For example:
5 ?- parent(X,Y).
X = pam,
Y = bob .
Isn't it supposed to give all the combinations that satisfy the relation parent?
Do anyone have idea what the problem is?

don't hit enter after your first results shows, use spacebar instead
[Enter] stops execution even if the backtracking is not completed yet
[Spacebar] or [;] continues with backtracking from your last result to the next result or false if there are no other results left.

Related

Prolog beginner. How to take list as parameter and pass it on

I am a total beginner at Prolog. I am struggling with creating a rule, which takes a list as parameter and passes the list onto another rule. Here is my code:
combine([], '').
combine([L|List], Total) :-
combine(List, CombinedRest),
atom_concat(L, CombinedRest, Total).
findHeadline([W|Words], Combined) :-
combine(Words, Combined).
findHeadline2([Words], Combined) :-
combine(Words, Combined).
findHeadline works as expected, but findHeadline2 does not. Here is the output:
1 ?- findHeadline([billig, enkeltmand], Combination).
Combination = enkeltmand.
2 ?- findHeadline2([billig, enkeltmand], Combination).
false.
The output I was expecting from findHeadline was:
Combination = billigenkeltmand.
How can it be that this does not work?
I tried to utilize trace in SWI-prolog, but it gave me no clue whatsoever, as the findHeadline rule just exits immediately and does not call the combine rule at all.
It is not very clear what it is exactly that you are after. If you just want to concatenate a list of atoms to get one atom, use atomic_list_concat/2 available in SWI-Prolog:
?- atomic_list_concat([foo, bar, baz], C).
C = foobarbaz.
At the moment, your findHeadline2/2 reads:
"Take a list containing exactly one element, and combine/2 that element."
This is not what you are after, I have the feeling.
Your findHeadline/2, on the other hand, says:
"Take a list of at least one element, and combine/2 all elements except the first".
This is important: never ever ignore compilation warnings. You get code that does something, but you can be almost certain that it does not do what you want it to do, which is bad, or that if someone else reads your code, they will be confused, which is also bad.

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.

False value returned in Prolog?

sitting(mary, james).
sitting(rosie, andrew).
sitting(kiera, tom).
issitting(X, Y) :- sitting(X, Y).
Hey guys, I basically want to check who the true or false values of who is sitting next to who,
When I type in the compiler
issitting(rosie, andrew).
A true value is returned, however, when I type
issitting(andrew, rosie).
A false value is returned (Which should be true because they are sitting next to each other). I don't want to add three extra lines of code should the user check for who is sitting next to each other (with all possible combinations).
How would you alter the rule to get Prolog to understand that if the user switches the names around, they're still true (NOT false).
I don't understand why it's giving me 'false' .
I'm stuck and this is the best I could get done so far :/
Thank you.
(I could just point out the problem, but then you would not learn anything. I assume you are using SWI, since you say that false is returned.)
?- issitting(andrew, rosie).
false.
Let me restate what your problem is: You are expecting that issitting(andrew, rosie) is true. But it is not. What would you do if you asked that question to a person? Probably you would ask why? Why isn't andrew sitting next to rosie? And, say, you did not understand the explanations, you might have asked another question:
Is andrew at least sitting next to anyone?
So this question is a generalization of the original question. In Prolog, we can do the very same thing with the help of variables like so:
?- issitting(andrew, Anyone).
false.
So now we know that andrew issitting next to nobody? Confused? Well, we can generalize the query once again:
Is there at least one person sitting next to anyone?
?- issitting(Person, Anyone).
Person = mary, Anyone = james
; Person = rosie, Anyone = andrew
; Person = kiera, Anyone = tom.
So there are some persons around. Effectively, the reason is that you have sitting/2 and another relation issitting/2. You need to generalize issitting/2 by adding the following rule:
issitting(X, Y) :- sitting(Y, X).
But the point was to show you a good general debugging strategy:
In case of unexpected failure, try to generalize your query (and your program).

SWI-Prolog How Prolog handles logical comparisons

I have written the following code in SWI-Prolog:
:- dynamic state_a/1 .
:- dynamic state_b/1 .
:- dynamic state_c/1 .
state_a([1,2,3,4,5,0]).
state_b([0]).
chop(LIST,HEAD,TAIL) :- LIST=[HEAD|TAIL].
move_ab :- !,state_a(X),
chop(X,Ha,Ba),
Ha>0,
state_b(Y),
chop(Y,Hb,Bb),!,
(Ha<Hb ; Hb =:= 0),
asserta(state_a(Ba)),asserta(state_b([Ha|Y])),
retract(state_a(X)), retract(state_b(Y));
write('Wrong Move.Choose Another').
There are 2 OR(;) in my code. When I ask move_ab in Prolog for the first time all the conditions before the second OR are true so i get the answer true from Prolog.
But the second time I ask move_ab in Prolog I get just the answer false.
I don't know how this can happen. Some of the conditions before the second OR are not true so Prolog should check the condition after the second OR and write me the message Wrong Move.Choose Another..
I tried using () to group the conditions but I still get the same message.
Any idea about what is going on? By the way I am a newb in Prolog, just started 2 days ago :)
The problem lies in the use of cut (!/0) before the conditions are properly tested. Cut removes choice points. Here it means that the choices are removed before you even test anything. So if the tests fail, everything fails !
BTW, manipulating the database is maybe not the best idea there. To represent states, you could use global variables as follows :
:- nb_setval(state_a, [1,2,3,4,5,0]).
:- nb_setval(state_b, [0]).
move_ab :-
nb_getval(state_a, [Ha|Ta]),
Ha > 0,
nb_getval(state_b, [Hb|Tb]),
(Ha < Hb ; Hb =:= 0),
nb_setval(state_a, Ta),
nb_setval(state_b, [Ha, Hb|Tb]),
!
;
write('Wrong Move.Choose Another').
A general advice given to beginners in prolog is to stay away from database manipulation if possible, as often problems are solvable without it. Here though it could be justified, but global variables will be faster and easier to manipulate.

Prolog Recursive Rules Wrong Result

i have define a recursive rule but the result seems incorrect.
customer(peter,bank(maybank),customertype(personal),
citizen(malaysian),age(62),credit(50000),
income(3000),property(car) ).
isseniorcitizen(X) :- customer(X, bank(_),customertype(_),
citizen(malaysian),age(Age),credit(_),
income(_),property(_)),
Age >= 60.
lowerinterest(Senior) :- isseniorcitizen(Senior).
isseniorcitizen(peter).
But the SWI-Prolog return
X = peter;
X = peter.
Why it return two times rather once ?
Please help.
Thanks.
The simple problem is that you have stated that peter is a senior citizen twice; first by first order logic in your program by adding him to the "database" on top, then by simply stating that he is a senior citizen at the bottom of your program. My previous answer (add a cut) is also correct but misses the problem; it would cancel the search of a unified variable X after having found peter to be a matching atom, and would hence not progress to other X-es than peter.

Resources