Reputation: 13
I'm working on an assignment for my prolog course, but I'm stuck on how to handle some of the clues for the logic puzzles and would very much appreciate some hints/tricks/assistance:
Billy, Fernando, Steven, and Zachary all have an appointment at the doctor's. Unfortunately the doc's computer system broke down and s/he doesn't remember who had backpain, heartburn, hip pain, or shingles, and whether the appointments were at 9am, 10am, 11am or at 12. But fortunately, the following clues where found:
So far I have this, but seeing how the zachary predicate results in an endless loop I'm fairly certain I have a wrong approach to it.
sublist( [], _ ).
sublist( [X|XS], [X|XSS] ) :- sublist( XS, XSS ).
sublist( [X|XS], [_|XSS] ) :- sublist( [X|XS], XSS ).
ziekte(X,Y,Z):-
Appointments = [0900,1000,1100,1200],
member(ziekte(Billy,_),Appointments),
member(ziekte(Fernando,_),Appointments),
member(ziekte(Steven,_),Appointments),
member(ziekte(Zachary,_),Appointments),
sublist([ziekte(Billy,_),ziekte(_,heartburn)],[0900,1100]),
sublist([ziekte(Billy,shingles),ziekte(Fernando,shingles)],Appointments).
ziekte(_,back-pain,Y) :-
ziekte(Zachary,_,X),
X > Y.
ziekte(_,hip-pain,0900) :-
ziekte(_,heartburn,1100).
ziekte(_,hip-pain,1000) :-
ziekte(_,heartburn,1200).
I find myself having a hard time getting my head around Prolog so thank you for any trouble to be taken.
Upvotes: 1
Views: 232
Reputation: 22803
There are several issues here. First of all, Prolog atoms are always lowercase or quoted; Billy
and Fernando
etc. are variables, which is probably not what you intend them to be, so you will need to fix that.
Second, there is some confusing code here:
Appointments = [0900,1000,1100,1200],
member(ziekte(Billy,_),Appointments),
What you're saying here is, "I have a list of numbers, [900,1000,1100,1200]
, and ziekte(V1,_)
is in it." This is clearly false--there are no ziekte/2
structures in this list.
I suspect you may be suffering from the most-common ailment of the beginning Prolog programmer: belief that Prolog relations "return" values. Do you think ziekte(Billy,_)
is going to somehow cause ziekte/3
to be called below, and somehow the third argument of the relation will appear in this location? It will not--there is no relationship between the structure ziekte(_,_)
and the predicate ziekte/3
defined below, and Prolog does not evaluate nested expressions like this at all.
What does member(X, List)
do? It attempts to unify X
with each value of List
. Suppose you have a list that looks like L = [appointment(zachary,back-pain,1100), appointment(steven,X,Y), appointment(Z,heartburn,900), ...]
. What does member(appointment(billy,Ailment,900), L)
do? It tries to unify:
appointment(billy,Ailment,900) = appointment(zachary,back-pain,1100)
fails
appointment(billy,Ailment,900) = appointment(steven,X,Y)
fails
appointment(billy,Ailment,900) = appointment(Z,heartburn,900)
succeeds with
Ailment = heartburn
Z = billy
If you find this surprising, you need to think harder about unification!
The reason you have infinite recursion is because your predicate ziekte/3
calls itself. Look at the trace:
trace, ziekte(X,Y,Z).
Call: (8) ziekte(_G4078, _G4079, _G4080) ?
Call: (9) _G4239=[900, 1000, 1100, 1200] ?
Exit: (9) [900, 1000, 1100, 1200]=[900, 1000, 1100, 1200] ?
Call: (9) lists:member(ziekte(_G4232, _G4233), [900, 1000, 1100, 1200]) ?
Fail: (9) lists:member(ziekte(_G4232, _G4233), [900, 1000, 1100, 1200]) ?
Redo: (8) ziekte(_G4078, _G4079, _G4080) ?
Call: (9) ziekte(_G4230, _G4231, _G4232) ?
Call: (10) _G4242=[900, 1000, 1100, 1200] ?
Exit: (10) [900, 1000, 1100, 1200]=[900, 1000, 1100, 1200] ?
Call: (10) lists:member(ziekte(_G4235, _G4236), [900, 1000, 1100, 1200]) ?
Fail: (10) lists:member(ziekte(_G4235, _G4236), [900, 1000, 1100, 1200]) ?
Redo: (9) ziekte(_G4230, _G4231, _G4232) ?
Call: (10) ziekte(_G4233, _G4234, _G4235) ?
Call: (11) _G4245=[900, 1000, 1100, 1200] ?
Exit: (11) [900, 1000, 1100, 1200]=[900, 1000, 1100, 1200] ?
Call: (11) lists:member(ziekte(_G4238, _G4239), [900, 1000, 1100, 1200]) ?
Fail: (11) lists:member(ziekte(_G4238, _G4239), [900, 1000, 1100, 1200]) ?
Redo: (10) ziekte(_G4233, _G4234, _G4235) ?
What's happening here is this: you want to enter ziekte(X,Y,Z)
. Prolog finds the first clause, the one with the head ziekte(X,Y,Z)
. It immediately forms the list of appointment times. Then it checks to see if there is a ziekte/2
structure in it. This fails. Prolog backtracks and tries the next clause: the one with the head ziekte(_,back-pain,Y)
. The first expression in the body of this clause is ziekte(Zachary,_,X)
. We recur: Prolog finds the first clause of ziekte
and we are right back where we started.
Now you still have other problems. Notice you get a lot of singleton variable warnings. Begin treating these as fatal errors.
Your rule clauses look extremely strange to me. I don't know how they could possibly work, to be frank.
I think you're very lost here! I would strongly recommend you review the basics of Prolog. You can't fake it until you make it with Prolog, it really is completely different from everything else!
If I were you, I would begin by mapping out the domain with facts like patient/1
, time/1
and ailment/1
. I made significant use of select/3
in my solution, so I would review that. Also plus/3
. Make sure you have a concrete understanding of the differences (and similarities) between structs--when evaluation will happen and when it will not. Then come back and try again!
Edit: Comments on the pastebin code.
The main problem with your pasted code is that you're trying to generate permutations with sublist/2
, but what it does is give you ordered subsets. Your first pass through you have already generated a solution set, which fails, and then you spend the rest of your time in sublist/2
.
Check this out:
?- ziekte(Y), sublist([Y1,Y2,Y3,Y4], Y).
Y = [backpain, heartburn, hippain, shingles],
Y1 = backpain,
Y2 = heartburn,
Y3 = hippain,
Y4 = shingles ;
false.
This only has one solution, so you're only really trying one permutation. By the time you hit the line with member([billy,_,Tijd1], Opl)
, you've already set up Opl = [[billy, backpain, 900], [fernando, heartburn, 1000], [steven, hippain, 1100], [zachary, shingles, 1200]]
. This would be fine if you were using something to permute the lists to generate different assignments, but the preceeding sublist/2
calls have no more solutions, so there will not be any other assignments to X1..X4, Y1..Y4, Z1..Z4, so you're failing because the only solution you generated does not succeed.
Upvotes: 1