我正在学习Prolog。我写了几个简单的事实和规则:
heavier(X,Y) :- lighter(Y,X).
heavier(horse,mouse).
lighter(X,Y) :- heavier(Y,X).
然后我问了这个问题:
lighter(mouse,horse).
我得到了以下错误:
Fatal Error: local stack overflow (size: 16384 Kb, reached: 16383 Kb, environment variable used: LOCALSZ)
这个程序有什么问题?
答案 0 :(得分:2)
我已在此处复制您的条款,为方便起见编号:
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条的顺序。如果你切换它们,它首先会尝试评估成功的事实 heavier(horse, mouse).
,所以你的查询{{1 }}返回lighter(mouse,horse).
。太好了!
但那只是它的一半。让我们对这些条款重新排序,并询问是否true
需要一段时间,不是吗?那是因为无限循环仍在发生。现在事实永远不会匹配,因为它涉及老鼠而不是鸟类,并且解释器只是循环通过你的循环定义。它没有任何记忆选项,因此堆栈永远不会溢出(或者至少没有那么快),但我们仍然没有得到答案。
解决这个问题的方法是将你的事实与你的定义分开。
lighter(bird, horse).
这应该可以解决问题。
答案 1 :(得分:1)
您可以使用trace/0
检查程序的工作方式,而且您会知道,heavier(X,Y) :- lighter(Y,X).
规则就在heavier(horse,mouse).
之前,因此永远不会达到第二条规则,这就是为什么您的程序是只是无限循环