问题
I cannot figure out why the following query from the given Prolog code generates the error Out of local stack
.
Prolog code:
likes(g,c).
likes(c,a).
likes(c,b).
likes(b,a).
likes(b,d).
likes(X,Z) :- likes(X,Y), likes(Y,Z).
the query
?- likes(g,X).
results in
X = c ;
X = a ;
X = b ;
ERROR: Out of local stack
Edit 1 This is the way I think that Prolog should deal with this query,
likes(g,c) is a fact, so X={c}
likes(g,b) <= likes(g,c) and likes(c,b), so X={c,b}
likes(g,a) <= likes(g,b) and likes(b,a), so X={c,b,a}
likes(g,d) <= likes(g,b) and likes(b,d), so X={c,b,a,d}
likes(g,a) and false, so nothing to add to X
likes(g,d) and false, so nothing to add to X
end of backtracking search.
Edit 2 I managed to get what I was looking for by the following modification of the code:
likes(g,c).
likes(c,a).
likes(c,b).
likes(b,a).
likes(b,d).
indirect_likes(A,B):- likes(A,B).
indirect_likes(A,C):- likes(B,C), indirect_likes(A,B).
the query
?- indirect_likes(g,Which).
results in
Which = c ;
Which = a ;
Which = b ;
Which = a ;
Which = d ;
false.
However, there is still something which I cannot figure out the rationale behind. If I change the last rule to be
indirect_likes(A,C):- indirect_likes(A,B), likes(B,C).
Then I get ERROR: Out of local stack
! As far as I know, logical conjunction is commutative.
回答1:
To get the transitive-closure of binary relation R_2
, use meta-predicate closure/3 like so:
?- closure(R_2,From,To).
Let's run a sample query of closure/3
together with likes/2
!
?- closure(likes,X,Y). X = g, Y = c ; X = g, Y = a ; X = g, Y = b ; X = g, Y = a % redundant ; X = g, Y = d ; X = c, Y = a ; X = c, Y = b ; X = c, Y = a % redundant ; X = c, Y = d ; X = b, Y = a ; X = b, Y = d ; false. % query terminates universally
We get the same answers when we use indirect_likes/2
, but in a different order:
?- indirect_likes(X,Y). X = g, Y = c ; X = c, Y = a ; X = c, Y = b ; X = b, Y = a ; X = b, Y = d ; X = g, Y = a ; X = g, Y = b ; X = c, Y = a % redundant ; X = g, Y = a % redundant ; X = c, Y = d ; X = g, Y = d ; false. % query terminates universally
As you stated in your comments to @C.B.'s answer, binary relations are not necessarily reflexive and/or symmetric. With the definition you gave, likes/2
is neither:
?- likes(X,X).
false. % not reflexive (not even close)
?- likes(X,Y), likes(Y,X).
false. % not symmetric (not even close)
So far, so good!
Let's tentatively add the following additional fact to your database:
likes(b,b).
With this expanded definition, indirect_likes/2
behaves erratically:
?- indirect_likes(b,b). true ; true ; true ... % does not terminate universally ?- indirect_likes(X,Y), false. % do we get finite failure? ... % no! query does not terminate universally
What can we do? Let's use meta-predicate closure/3
with the expanded version of likes/2
!
?- closure(likes,b,b). true % succeeds non-deterministically ; false. % query terminates universally ?- closure(likes,X,Y), false. % do we get finite failure? false. % yes! query terminates universally
The bottom line?
In pure Prolog, conjunction is commutative, as far as the logical meaning is concerned.
Due to Prolog's SLD resolution, the goal false,repeat
finitely fails, but repeat,false
does not.
The programmer needs to take care of termination, but usually this is a small price to pay for the raw performance and control that Prolog offers.
In this answer I passed "termination worries" on to the implementor of meta-predicate closure/3 :)
回答2:
You spin off into infinite recursion.
Once you get to likes(b,a)
, you call likes(a,_G4382)
, which has no fact defined so it switches to the rule likes(X,Z) :- likes(X,Y), likes(Y,Z).
So it calls likes(a,_G4383)
which calls likes(X,Z) :- likes(X,Y), likes(Y,Z).
over and over and over.
You might want to define and auxillary predicate aux_likes/2
that hosts all your facts. This will only work if there are no circular relationships, i.e. aux_likes(b,c)
and aux_likes(c,b)
. You would also need to define likes(X,X).
This is essentially a graph problem and in graph theory a node has to be connected to itself. If you use it as a generator, it will go off into into infinite recursion (if you have cycles) unless you add cuts
which are not ideal.
If using swi-prolog
, feel free to enter the debug
or spy
query to see what's going on.
Code:
aux_likes(g,c).
aux_likes(c,a).
aux_likes(c,b).
aux_likes(b,a).
aux_likes(b,d).
likes(X,Z) :- aux_likes(X,Y), likes(Y,Z).
likes(X,X).
Output with new predicate:
?- likes(g,X),print(X),nl,fail.
a
a
d
b
c
g
false.
This says g
can like a
through c
or through b
. It likes d
through b
, it likes b
through c
and it likes c
directly. It also must like itself inorder to query like this. If you would rather have the usage mode (+,+)
meaning you supply it with both terms and no variables (as a checker) you can do
?- likes(g,c).
true .
来源:https://stackoverflow.com/questions/20979780/error-out-of-local-stack-in-my-prolog-code