问题
plays(alice, leadguitar).
plays(noah, drums).
plays(mike, leadguitar).
plays(mike, drums).
plays(katie, baseguitar).
plays(drew, leadguitar).
plays(drew, baseguitar).
duetwith(Person1,Person2):-
plays(Person1,L),
plays(Person2,L),
Person1 \= Person2.
I write a new rule called combo that determines whether or not three people can make a combo with a drummer, a base guitar, and a lead guitar.
combo(Person1,Person2,Person3):-
plays(Person1,X),
plays(Person2,Y),
plays(Person3,Z),
X \= Y,
Y \= Z,
X\=Z.
Can drew, alice, and mike make a combo?
combo(mike,alice,drew).
true so the answer is yes they can make a combo.
I need help understanding the steps the program takes to answer the above query in prolog. Any help with a list of steps is greatly appreciated so I can gain a deeper understanding of each step Prolog takes.
Here is an example of a list of steps Prolog takes for a different example just to give an idea of what I am looking for.
In the case of talkswith(bob,allen)
, the engine took the following steps:
In
talkswith(Person1,Person2):- speaks(Person1,L), speaks(Person2,L), Person1 \= Person2.
replace every occurrence of Person1
with bob
and Person2
with allen
to get
talkswith(bob,allen) :-
speaks(bob,L),
speaks(allen,L),
bob \= allen.
Let’s see if we can find a value for L that makes the right side true. Start with
speaks(bob,L).
What can L be? Here are our facts:- speaks(allen, russian).
- speaks(bob, english).
- speaks(mary, russian).
- speaks(mary, english).
In fact 1, the first slot isn’t bob, so that won’t work. In fact 2, the first slot is bob, so let’s try
L = english
inspeaks(allen,L), bob \= allen.
Now we are askingspeaks(allen,english), bob\= allen.
- Back to the knowledge base. Does
speaks(allen,english)
match a fact? Not fact 1, not fact 2, not fact 3, not fact 4. This fails. - Now we back up to step 2. Fact 2 didn’t work out, so let’s try fact 3. No, that isn’t bob. Fact 4 isn’t bob either. We can’t find a value for L that works, so the search failed.
回答1:
replace every occurrence of Person1 with bob
Prolog uses syntactic unification which never does replacement. A free variable can only be bound once to a value. If it looks like a variable is being changed more than once, it is not. There can be many stack frames and for each stack frame a new set of variables can be created.
Trace is somewhat helpful but I need to translate that into the form of the example above with the steps written out and explained in plain English.
For these facts
plays(alice, leadguitar).
plays(noah, drums).
plays(mike, leadguitar).
plays(mike, drums).
plays(katie, baseguitar).
plays(drew, leadguitar).
plays(drew, baseguitar).
and this predicate
combo(Person1,Person2,Person3):-
plays(Person1,X),
plays(Person2,Y),
plays(Person3,Z),
X \= Y,
Y \= Z,
X\=Z.
and this query
combo(mike,alice,drew).
First read SWI-Prolog Debugging and Tracing Programs
Run the query with trace, unify port enabled and leashing off.
?- visible(+unify).
true.
?- leash(-all).
true.
?- trace.
true.
[trace] ?- combo(mike,alice,drew).
Call: (8) combo(mike, alice, drew)
Unify: (8) combo(mike, alice, drew)
Call: (9) plays(mike, _7040)
Unify: (9) plays(mike, leadguitar)
Exit: (9) plays(mike, leadguitar)
Call: (9) plays(alice, _7040)
Unify: (9) plays(alice, leadguitar)
Exit: (9) plays(alice, leadguitar)
Call: (9) plays(drew, _7040)
Unify: (9) plays(drew, leadguitar)
Exit: (9) plays(drew, leadguitar)
Call: (9) leadguitar\=leadguitar
Fail: (9) leadguitar\=leadguitar
Redo: (9) plays(drew, _7040)
Unify: (9) plays(drew, baseguitar)
Exit: (9) plays(drew, baseguitar)
Call: (9) leadguitar\=leadguitar
Fail: (9) leadguitar\=leadguitar
Redo: (9) plays(mike, _7040)
Unify: (9) plays(mike, drums)
Exit: (9) plays(mike, drums)
Call: (9) plays(alice, _7040)
Unify: (9) plays(alice, leadguitar)
Exit: (9) plays(alice, leadguitar)
Call: (9) plays(drew, _7040)
Unify: (9) plays(drew, leadguitar)
Exit: (9) plays(drew, leadguitar)
Call: (9) drums\=leadguitar
Exit: (9) drums\=leadguitar
Call: (9) leadguitar\=leadguitar
Fail: (9) leadguitar\=leadguitar
Redo: (9) plays(drew, _7040)
Unify: (9) plays(drew, baseguitar)
Exit: (9) plays(drew, baseguitar)
Call: (9) drums\=leadguitar
Exit: (9) drums\=leadguitar
Call: (9) leadguitar\=baseguitar
Exit: (9) leadguitar\=baseguitar
Call: (9) drums\=baseguitar
Exit: (9) drums\=baseguitar
Exit: (8) combo(mike, alice, drew)
true.
Call: (8) combo(mike, alice, drew)
Prolog looks for a predicate that matches the query. When Prolog looks for a predicate it searches by predicate name, in this case combo
, and arity, in this case 3
and finds only one predicate with one clause. Prolog also searches for predicates in the order they appear in the source code. There is more to it (indexing) but that level of detail is not needed to explain this simple query.
Unify: (8) combo(mike, alice, drew)
Once Prolog has found a clause/fact based on predicate name and arity it checks that the query and head of the clause or fact can be unified.
mike
unifies with Person1
. Person1
is now bound to mike
.alice
unifies with Person2
. Person2
is now bound to alice
.drew
unifies with Person3
. Person3
is now bound to drew
.
Call: (9) plays(mike, _7040)
If the previous statement unifies, then the next statement is called. Each statement is a query in itself. So running the query plays(mike,X).
as a stand alone query is the same as this statement in the clause. There are many facts for plays/2
and two of them match plays(mike,X).
Prolog uses the first one it finds, however since there are more than one, a choice point is made. We will call this specific choice point plays(mike,X) - cp1
and refer back a specific choice point when a corresponding REDO is encountered.
Unify: (9) plays(mike, leadguitar)
Once Prolog has found a clause/fact based on predicate name and arity it checks that the query and head of the clause can be unified.
plays
unifies with plays
mike
unifies with mike
_7040
unifies with leadguitar
. _7040
is bound to leadguitar
.
Exit: (9) plays(mike, leadguitar)
This is just completing the ports of the Prolog box model. It shows the result of Call: (9) plays(mike, _7040)
. No unification takes place for this statement.
Call: (9) plays(alice, _7040)
Unify: (9) plays(alice, leadguitar)
Exit: (9) plays(alice, leadguitar)
Same pattern for alice
. Alice has only one fact so not choice points generated for her.
Call: (9) plays(drew, _7040)
Unify: (9) plays(drew, leadguitar)
Exit: (9) plays(drew, leadguitar)
Same pattern for drew
. Since drew has two facts for plays(drew,X).
a choice point is generated. plays(drew,X) - cp1
Call: (9) leadguitar\=leadguitar
This is the fourth statement X \= Y
with X
is bound to leadguitar
and Y
is bound to leadguitar
Fail: (9) leadguitar\=leadguitar
Since leadguitar
is not different from leadguitar
this query fails. Upon failure Prolog goes back to the last choice point (Redo) and tries to find another solution.
Redo: (9) plays(drew, _7040)
Remember the last choice point created, plays(drew,X) - cp1
. Since something failed the query is tried with another possible solution. Since the first choice point for plays(drew,X)
failed with X
being leadguitar
, the second fact is used, plays(drew,baseguitar).
Unify: (9) plays(drew, baseguitar)
Just shows that the second fact for plays(drew,X)
is being used.
Exit: (9) plays(drew, baseguitar)
It shows the result of Redo: (9) plays(drew, _7040)
.
The remainder is just more copy/paste of what has been done already and changing out the statements, variables, bound values, etc.
This answer is similar, but has more detail.
Of note is this question
I write a new rule called combo that determines whether or not three people can make a combo with a drummer, a base guitar, and a lead guitar.
is not answered by this query
combo(Person1,Person2,Person3):-
plays(Person1,X),
plays(Person2,Y),
plays(Person3,Z),
X \= Y,
Y \= Z,
X\=Z.
because if these facts are added
plays(alice, flute).
plays(noah, cello).
plays(mike, trumpet).
this query
?- combo(alice,noah,mike).
true ;
true .
says true but alice
, noah
and mike
are not playing the leadguitar, drums, and baseguitar.
来源:https://stackoverflow.com/questions/53470483/prolog-explain-trace-steps-in-english