我有这个例子:
descend(X,Y) :- child(X,Y).
descend(X,Y) :- child(X,Z), descend(Z,Y).
child(anne,bridget).
child(bridget,caroline).
child(caroline,donna).
它运作良好,我了解。这是一个小练习的解决方案。我的解决方案是相同的,但不断变化:
降序(X,Y):-降序(X,Z),降序(Z,Y)。
也就是说,在第二个
child
规则中将descend
更改为descend
。如果我在第一个解决方案中查询
descend(X, Y).
,则会获得:?- descend(X, Y).
X = anne,
Y = bridget ;
X = bridget,
Y = caroline ;
X = caroline,
Y = donna ;
X = anne,
Y = caroline ;
X = anne,
Y = donna ;
X = bridget,
Y = donna ;
false.
哪个是正确的。但是,如果我使用相同的解决方案进行查询,则会得到:
?- descend(X, Y).
X = anne,
Y = bridget ;
X = bridget,
Y = caroline ;
X = caroline,
Y = donna ;
X = anne,
Y = caroline ;
X = anne,
Y = donna ;
ERROR: Out of local stack
它没有说
X = bridget,Y = donna ;
,它也溢出了。我知道为什么会溢出。我不明白的是为什么它没有找到最后的关系。是因为溢出吗?如果是这样,为什么? (为什么堆栈这么少的知识堆这么大?)。如果我查询
descend(bridget, donna)
,它将回答yes
。我在构想探索树时遇到问题...
除了这个问题之外,我想原来的解决方案更有效(忽略了我的最后进入无限循环这一事实),不是吗?
谢谢!
最佳答案
我在想象探索树时遇到问题...
是的,这在Prolog中非常困难。如果您的数据库更大,那就更糟了!但是大多数时候,没有必要设想非常精确的搜索树。相反,您可以使用几个非常可靠的概念。
记住您是如何制定查询的。您在另一个解决方案上看了看。但是您真正感兴趣的是查询是否终止。您可以通过添加 false
来解决问题,而无需查看解决方案。
?-下降(X,Y),否。
错误:超出本地堆栈
此查询永远不能为真。它可能失败,溢出或循环,或者产生另一个错误。剩下的是一个非常有用的概念:通用终止或在这种情况下为非终止。
这可以扩展到您的实际程序:
下降(X,Y):-假,孩子(X,Y)。
降序(X,Y):-降序(X,Z),假,降序(Z,Y)。
如果这个称为failure-slice的片段没有终止,那么您的原始程序也不会终止。看看这个程序的其余部分!甚至child/2
也不再存在。因此,我们可以得出结论child/2
不会影响非终止! Y
仅出现一次。而且X
绝不会导致失败。因此descend/2
终止从不终止!
因此,该结论比有关特定搜索树的陈述要笼统得多。这是关于所有人的声明。
如果您仍然想对解决方案的非常精确的顺序进行推理,那么您将不得不进行实际执行。但是为什么要打扰呢?这非常复杂,特别是如果您的child/2
关系包含循环。您可能会混淆事物并建立不准确的理论(至少我做到了)。无需其他崇拜。我已经放弃了“一步一步”完成这么多细节。而且我不会错过。