ERROR: Out of local stack in my Prolog code

╄→尐↘猪︶ㄣ 提交于 2019-12-22 12:27:07

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!