我在这里复制了您的条款,为方便起见编号:
heavier(X,Y) :- lighter(Y,X). %1
heavier(horse,mouse). %2
lighter(X,Y) :- heavier(Y,X). %3
所以让我们弄清楚解释器要做什么。
- 你问过它
lighter(mouse,horse). 匹配 3,与 X = mouse 和 Y = horse。
- 它现在需要知道
heavier(horse, mouse) 是否为真。这匹配 1,与 X = horse 和 Y = mouse。
- 现在需要知道
lighter(mouse,horse) 是否为真。匹配 3,与 X = mouse 和 Y = horse。 嘿,等一下!
由于解释器从顶部开始,当评估heavier/2时,它总是从第一个子句开始,这使得它想要评估lighter/2,这使得它想要评估heavier/2,它以第一个子句...您可能会看到它的标题。
但这不仅仅是无限循环。你看,当解释器决定使用第一个子句时,它知道还有另一个匹配的子句。每次它决定评估第一个子句时,它也会记住另一个选项。未使用的选项堆栈不断增长,不断增长......直到堆栈溢出。
所以直接的问题是子句 1 和 2 的顺序。如果你切换它们,它首先会尝试评估 fact heavier(horse, mouse). 成功,所以你的查询 lighter(mouse,horse). 返回 @ 987654336@。太好了!
但这只是其中的一半。让我们重新排序这些子句,并询问lighter(bird, horse).
需要一些时间,不是吗?那是因为无限循环仍在发生。现在这个事实永远不会匹配,因为它涉及的是老鼠而不是鸟,而解释器只是不断地循环遍历你的循环定义。它没有任何要记住的选项,因此堆栈永远不会溢出(或者至少没有那么快),但我们仍然没有得到答案。
对此的解决方案是将您的事实与您的定义分开。
heavier(X, Y) :- is_heavier(X, Y).
heavier(X, Y) :- is_lighter(Y, X).
lighter(X, Y) :- heavier(Y, X).
is_heavier(horse, mouse).
is_lighter(bird, horse).
这应该可以解决问题。