这是我的计划:
depends(apple, tree).
depends(cider, apple).
depends(X,Y) :- X\==Y, depends(Z,Y),depends(X,Y).
如果我问下列问题:
depends(cider, tree).
我明白了:
GNU Prolog 1.3.0
By Daniel Diaz
Copyright (C) 1999-2007 Daniel Diaz
| ?- [apples].
apples.pro for byte code...
apples.pro compiled, 4 lines read - 765 bytes written, 28 ms
yes
| ?- depends(cider, tree).
Fatal Error: local stack overflow (size: 8192 Kb, environment variable used: LOCALSZ)
如果我运行'追踪',我可以看到X \ == Y的评价一遍又一遍地重复......
我在这里做错了什么? (除了购买'Seven Languages in Seven Weeks'的副本:-))
编辑:
所以这要归功于Daniel Lyons的笔记:将事实的名称与规则的名称区分开来阻止了递归:
depends(apple, tree).
depends(cider, apple).
depends_on(X,Y) :- depends(X,Z),depends(Z,Y).
给出以下内容(打开'trace'):
{trace}
| ?- depends_on(cider, tree).
1 1 Call: depends_on(cider,tree) ?
2 2 Call: depends(cider,_79) ?
2 2 Exit: depends(cider,apple) ?
3 2 Call: depends(apple,tree) ?
3 2 Exit: depends(apple,tree) ?
1 1 Exit: depends_on(cider,tree) ?
yes
答案 0 :(得分:4)
首先,你有一个单例变量:
depends(X,Y) :- X\==Y, depends(Z,Y),depends(X,Y).
相当于:
depends(X,Y) :- X\==Y, depends(_,Y), depends(X,Y).
Prolog"警告"关于单变量变量,你应该总是把它当作一个严重的错误,因为它几乎总是意味着你的代码没有按照你的想法去做。在这种情况下,我怀疑你认为Prolog会自动使X和Z不同,但它没有,而且这里没有别的指示Prolog用Z做某事,所以这只是浪费时间或真实问题的副本。
真正的问题是这段代码简化了这个:
depends(X,Y) :- X\==Y, depends(X,Y).
这是无限的递归。我可以给depends(chickens, eggs_and_flapjacks)
而Prolog只是说,"嗯,chickens
与eggs_and_flapjacks
不一样,我接下来要做的事情是什么?"然后跳回到开头只再问这个问题。这会导致堆栈溢出异常。如果您追踪,您将清楚地看到错误:
?- trace, depends(eggs, chickens).
Call: (7) depends(eggs, chickens) ?
Call: (8) eggs\==chickens ?
Exit: (8) eggs\==chickens ?
Call: (8) depends(eggs, chickens) ?
Call: (9) eggs\==chickens ?
Exit: (9) eggs\==chickens ?
Call: (9) depends(eggs, chickens) ?
Call: (10) eggs\==chickens ?
Exit: (10) eggs\==chickens ?
Call: (10) depends(eggs, chickens) ?
Call: (11) eggs\==chickens ?
Exit: (11) eggs\==chickens ?
Call: (11) depends(eggs, chickens) ?
Call: (12) eggs\==chickens ?
Exit: (12) eggs\==chickens ?
Call: (12) depends(eggs, chickens) ?
等。等
这就是你的整个问题。除了循环之外,你的代码还没有做任何事情。
修改图表遍历
您需要将此事实与谓词分开才能解决此特定问题。事情并非总是如此。你会想要这个:
depends_on(X, Y) :- depends(X, Y).
depends_on(X, Z) :- depends(X, Y), depends_on(Y, Z).
这为你提供了有限的递归。如果您尝试使用一个谓词,那么您将获得无限递归:
depends(X,Z) :- depends(X,Y), depends(Y,Z).
有几种方法可以解决这个问题,最简单的方法是将事实与谓词分开,就像我们上面所做的那样。一些Prolog实现支持tabling,我相信这也解决了这个问题(我高吗?);否则你可以跟踪你已经遍历过的关系并避免这种循环(这是处理无向图时的常用方法)。