我有下一个规则
% Signature: natural_number(N)/1
% Purpose: N is a natural number.
natural_number(0).
natural_number(s(X)) :-
natural_number(X).
ackermann(0, N, s(N)). % rule 1
ackermann(s(M),0,Result):-
ackermann(M,s(0),Result). % rule 2
ackermann(s(M),s(N),Result):-
ackermann(M,Result1,Result),
ackermann(s(M),N,Result1). % rule 3
查询为:ackermann (M,N,s(s(0)))
。
现在,据我所知,在第三次计算中,我们得到了一个无限的搜索(失败分支)。我检查一下,我得到了一个有限的搜索(失败分支)。
我将解释:在第一个中,我们得到了M = 0,N = s(0)的替换(规则1 - 成功!)。在第二个中,我们得到M = s(0)的替换,N = 0(规则2 - 成功!)。但现在呢?我尝试匹配M = s(s(0))N = 0,但它有一个有限搜索 - 失败分支。编译器为什么不写“失败”。
谢谢。
答案 0 :(得分:8)
答案 1 :(得分:5)
让我重新解释一下你的问题:查询ackermann(M,N,s(s(0))).
找到两个解决方案然后循环。理想情况下,它会在这两个解决方案之后终止,因为没有其他N
和M
的值为s(s(0))
。
那为什么查询不会普遍终止?理解这一点可能非常复杂,最好的建议是不尝试理解精确的执行机制。有一个非常简单的原因:Prolog的执行机制结果是复杂的,如果你试图通过代码来理解它,你很容易误解它。
相反,您可以尝试以下操作:在程序中的任何位置插入目标false
。如果生成的程序没有终止,那么原始程序也不会终止。
在你的情况下:
ackermann(0, N, s(N)) :- false.ackermann(s(M),0,Result):- false,ackermann(M,s(0),Result). ackermann(s(M),s(N),Result):- ackermann(M,Result1,Result), false,ackermann(s(M),N,Result1).
我们现在可以删除第一条和第二条规则。在第三条规则中,我们可以在错误后删除目标。因此,如果以下片段没有终止,原始程序也不会终止。
ackermann(s(M),s(N),Result):-ackermann(M,Result1,Result), false.
此程序现在仅在第一个参数已知时终止。但在我们的情况下它是免费的......
即:通过考虑程序的一小部分,我们已经能够推断出整个程序的属性。有关详细信息,请参阅网站上的this paper和其他人。
不幸的是,这种推理仅适用于非终止案件。对于终止,事情更复杂。最好的方法是尝试像cTI这样的工具,它可以推断终止条件,并试图证明它们的最优性。我已经输入你的程序,所以尝试修改if和看到效果!
如果我们在这里:这个小片段还告诉我们第二个参数不会影响终止 1 。这意味着,像ackermann(s(s(0)),s(s(0)),R).
这样的查询会
也不会终止。交换目标,看看差异......
1确切地说,不与s(_)
统一的术语将影响终止。想想0
。但任何s(0)
,s(s(0))
,......都不会影响终止。