Neverendingsearch
Neverendingsearch

Reputation: 13

Prolog list puzzle

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

Answers (1)

Daniel Lyons
Daniel Lyons

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

Related Questions