你的程序中发生了什么?它是永远循环,还是只需要一些时间,因为您最近几十年没有更新您的硬件?我们不能说。(实际上,我们可以通过查看您的程序来判断,但目前这太复杂了)。
我们可以轻松地做的是缩小这种代价高昂的努力的来源。而这,在没有深入了解你的程序的情况下。让我们从查询开始:
| ?- multiple(X, s(s(s(s(s(s(0))))))).
X = s(0) ? ;
X = s(s(0)) ? ;
X = s(s(s(0))) ? ;
X = s(s(s(s(s(s(0)))))) ? ;
** LOOPS or takes too long ***
没有更简单的方法可以做到这一点吗?所有这些分号打字。相反,只需添加false
到您的查询中。通过这种方式,找到的解决方案不再显示,我们可以专注于这个烦人的循环。而且,如果我们愿意,您还可以将false
目标添加到您的计划中!通过这样的目标,推理的数量可能会减少(或保持不变)。如果生成的片段(称为failure-slice)正在循环,那么这就是您的原始程序循环的原因:
多个(_X,0):-假。
多重(X,Y):- lt(0,X),假,lt(0,Y),差异(Y,X,D),多重(X,D)。
natNum(0) :-假。
natNum(s(X)) :- natNum(X), false。
lt(0,s(X)) :- natNum(X), false。
lt(s(X),s(Y)) :- false , lt(X,Y)。
?- 多个(X, s(s(s(s(s(s(s(0))))))), false。
** 循环 ***
你认识你的程序吗?只剩下循环所需的那些部分。而且,实际上在这种情况下,我们有一个无限循环。
为了解决这个问题,我们需要修改剩余的可见部分。我会选择lt/2
谁的第一个子句可以概括为lt(0, s(_))
.
可是等等!为什么可以概括我们有一个自然数的要求?看看multiple(X,0).
你写的事实。你也没有要求这X
是一个自然数。这种过度概括经常出现在 Prolog 程序中。它们以相对较低的价格改进了终止属性:有时它们过于笼统,但所有额外适合概括的术语都不是自然数。它们是类似any
or的术语[a,b,c]
,因此如果它们出现在某个地方,您就知道它们不属于解决方案。
所以想法是将false
目标放入您的程序中,以使生成的程序(故障切片)仍然循环。在最坏的情况下,你放false
错了地方,程序就会终止。通过反复试验,您可以获得最小的故障片。那些现在被划过的东西都无关紧要了!特别是diff/3
。所以不需要理解它(暂时)。看看剩下的程序就足够了。