问题
Clue
Four guests (Colonel Mustard, Professor Plum, Miss Scarlett, Ms. Green) attend a dinner party at the home of Mr. Boddy. Suddenly, the lights go out! When they come back, Mr Boddy lies dead in the middle of the table. Everyone is a suspect. Upon further examination, the following facts come to light:
- Mr Boddy was having an affair with Ms. Green.
- Professor Plum is married to Ms. Green.
- Mr. Boddy was very rich.
- Colonel Mustard is very greedy.
- Miss Scarlett was also having an affair with Mr. Boddy.
There are two possible motives for the murder:
- Hatred: Someone hates someone else if that other person is having an affair with his/her spouse.
- Greed: Someone is willing to commit murder if they are greedy and not rich, and the victim is rich.
Part A: Write the above facts and rules in your Prolog program. Use the following names for the people: colMustard, profPlum, missScarlet, msGreen, mrBoddy. Be careful about how you encode (or don’t encode) symmetric relationships like marriage - you don’t want infinite loops! married(X,Y) :- married(Y,X) % INFINITE LOOP
?-suspect(Killer,mrBoddy)
Killer = suspect_name_1
Killer = suspect_name_2
etc.
Part B: Write a predicate, suspect/2, that determines who the suspects may be, i.e. who had a motive.
?-suspect(Killer,mrBoddy)
Killer = unique_suspect.
Part C: Add a single factto your database that will result in there being a unique suspect. Clearly indicate this line in your source comments so that it can be removed/added for grading.
?-suspect(Killer,mrBoddy)
Killer = unique_suspect.
Whenever I type in
suspect(Killer,mrBoddy).
I get
suspect(Killer,mrBoddy).
Killer = profPlum
I'm missing
Killer = colMustard.
Here's my source.
%8) Clue
%facts
affair(mrBoddy,msGreen).
affair(missScarlett, mrBoddy).
affair(X,Y) :- affair(X,Y), affair(Y,X).
married(profPlum, msGreen).
married(X,Y) :- married(X,Y), married(Y,X).
rich(mrBoddy).
greedy(colMustard).
%rules
hate(X,Y) :- married(X,Spouse), affair(Y,Spouse).
greed(X,Y) :- greedy(X), not(rich(X)), rich(Y).
%suspect
suspect(X,Y):- hate(X,Y).
suspect(X,Y):- greed(X,Y).
回答1:
The problem is the recursive rules of the predicates affair/2
and married/2
. Attempting to use them easily leads to an endless loop (i.e. until the stack memory is exhausted). You must use a different predicate in each case to represent that if X is having an affair with Y, then Y is having an affair with X. You also need to change your definition of the suspect/2
predicate to call those new predicates.
To better understand why you get an endless loop, use the trace facilities of your Prolog system. Try:
?- trace, suspect(Killer, mrBoddy).
and go step by step.
回答2:
There are two kinds of problems with your program. One is on the procedural level: you observed that Prolog loops; the other is on the logical level — Prolog people call this rather the declarative level. Since the first annoying thing is this endless loop, let's first narrow that down. Actually we get:
?- suspect(Killer,mrBoddy).
Killer = profPlum ;
ERROR: Out of local stack
You have now several options to narrow down this problem. Either, go with the other answer and call up a tracer. While the tracer might show you the actual culprit it might very well intersperse it with many irrelevant steps. So many that your mind will overflow.
The other option is to manually modify your program by adding goals false
into your program. I will add as many false
goals as I can while still getting a loop. The big advantage is that this way you will see in your source the actual culprit (or to be more precise one of potentially many such culprits).1 After trying a bit, this is what I got as failure-slice:
?- suspect(Killer,mrBoddy), false.married(profPlum, msGreen) :- false. married(X,Y) :- married(X,Y), false,married(Y,X). hate(X,Y) :- married(X,Spouse), false,affair(Y,Spouse). suspect(X,Y):- hate(X,Y), false.suspect(X,Y):- false, greed(X,Y).
All remaining parts of your program were irrelevant, that is, they are no longer used. So essentially the rule
married(X,Y) :- married(X,Y), married(Y,X).
is the culprit.
Now, for the declarative part of it. What does this rule mean anyway? To understand it, I will interpret :-
as an implication. So provided what is written on the right-hand side is true, we conclude what is written on the left-hand side. In this case:
Provided
X
is married toY
andY
is married toX
we can conclude thatX
is married toY
.
This conclusion concluded what we have assumed to be true anyway. So it does not define anything new, logically. You can just remove the rule to get same results — declaratively. So married(profPlum, msGreen)
holds but married(msGreen, profPlum)
does not. In other words, your rules are not correct, as you claim.
To resolve this problem, remove the rule, rename all facts to husband_wife/2
and add the definition
married(M,F) :- husband_wife(M,F).
married(F,M) :- husband_wife(M,F).
So the actual deeper problem here was a logical error. In addition to that Prolog's proof mechanism is very simplistic, turning this into a loop. But that is not much more than a welcome excuse to the original logical problem.2
Footnotes:
1 This method only works for pure, monotonic fragments. Non-monotonic constructs like not/1
or (\+)/1
must not appear in the fragment.
2 This example is of interest to @larsmans.
来源:https://stackoverflow.com/questions/20060840/prolog-rules-are-correct-but-not-outputting-the-way-its-supposed-to