Prolog的后继符号产生不完全的结果,并无限循环Prolog的后继符号产生不完全的结果,并无限循环

2019-05-13 13:01发布

我开始学习序言和第一次了解继任符号。

而这正是我了解在序言写皮亚诺公理。

参见第12页PDF :

sum(0, M, M).
sum(s(N), M, s(K)) :-
    sum(N,M,K).

prod(0,M,0).
prod(s(N), M, P) :-
    prod(N,M,K),
    sum(K,M,P).

我把乘法法则为序言。 然后,我做了查询:

?- prod(X,Y,s(s(s(s(s(s(0))))))).

这意味着找到6的基本因素。

下面是结果。

X = s(0),
Y = s(s(s(s(s(s(0)))))) ? ;
X = s(s(0)),
Y = s(s(s(0))) ? ;
X = s(s(s(0))),
Y = s(s(0)) ? ;
infinite loop

这个结果有两个问题:

  1. 不是所有的结果被示出,请注意,结果X = 6,Y = 1缺失。
  2. 它不会停止,除非我按Ctrl + C,然后选择退出。

所以...我的问题是:

  1. 这是为什么? 我试图切换“刺”和“和”左右。 生成的代码给了我所有的结果。 再次,这是为什么? 它还虽然死循环。
  2. 如何解决?

我读了无限循环,对方的回答。 不过,我会很感激的人回答在此基础上的场景。 它极大地帮助我。

Answer 1:

如果你想深入研究终止性质,使用程序的继任者,算术是一个理想的研究对象:你知道先验他们应该说明一下,这样你就可以专注于更多的技术细节。 你需要了解几个概念。

通用终止

解释它最简单的方法,就是要考虑Goal, false 。 这将终止当且仅当Goal终止普遍。 那就是:看着示踪剂是最无效的方法 - 他们会告诉你只有一个执行路径。 但是,你需要了解所有的人都在一次! 也从来不看答案,当你想终止普遍,他们只会让你分心。 你已经看到它上面:你有三个整齐和正确答案,只有你的程序循环。 因此,更好地“关闭”的答案与false 。 这将删除所有分心。

故障片

需要的下一个概念是,一个的故障片 。 以一个纯粹的单调逻辑程序,并扔在一些目标false 。 如果导致故障的片不会终止(通用),也将原来的程序不会。 在您为例,可以考虑:

prod(0,M,0) :- false.
prod(s(N), M, P) :-
    prod(N,M,K), false,
    sum(K,M,P).

这些false目标,有助于消除在你的程序无关的装饰品:剩余部分显示你清楚,为什么prod(X,Y,s(s(s(s(s(s(0))))))). 不会终止。 它不会终止,因为碎片不关心P在所有! 你希望的是,第三个参数将有助于使prod/3中止,但片段显示了你,这是一切都是徒劳的,因为P不以任何目标发生。 无需繁琐的示踪剂。

往往是不那么容易找到最小的故障片。 但是,一旦你找到一个,它旁边的琐碎,以确定其终止或者说未结束的属性。 一段时间后,你可以用你的直觉想象一个切片,然后你可以用你的理由来检查,如果该片是相关的或不是。

什么是如此显着的了解失败的切片的概念是这样的:如果你想提高节目, 在参加上述片段可见修改你的程序! 只要你不改变它,这个问题将长期存在。 故障切片因此你的程序非常相关部分。

终止推断

这是你需要的最后一件事:一个终止inferencer(或分析器),如CTI将帮助您快速识别终止条件。 看的推断终止条件prod/3和改进prod2/3 在这里 !


编辑:既然这是一门功课的问题,我还没有发布最终的解决方案。 但要清楚,这里是到目前为止所获得的终止条件:

    prod(A,B,C)terminates_if b(A),b(B).
    prod2(A,B,C)terminates_if b(A),b(B);b(A),b(C).

因此,新的prod2/3是严格比原来的方案更好!

现在,它是由你来找到最终方案。 它的终止条件是:

   prod3(A,B,C)terminates_if b(A),b(B);b(C).

首先,试图找到故障切片prod2(A,B,s(s(s(s(s(s(0))))))) 我们希望它终止,但它仍然没有。 因此,采取的程序和手动添加false目标! 其余部分将向您展示的关键!

作为最后一个暗示:你需要添加一个额外的目标和一个事实。


编辑:根据要求,这里是失败切片prod2(A,B,s(s(s(s(s(s(0)))))))

prod2(0,_,0) :- false.
prod2(s(N), M, P) :-
   sum(M, K, P),
   prod2(N,M,K), false.

sum(0, M, M).
sum(s(N), M, s(K)) :- false,
    sum(N,M,K).

请注意的显著简化定义sum/3 。 它只是说:0加什么什么事情。 不再。 因此即使是更专业的prod2(A,0,s(s(s(s(s(s(0)))))))将循环而prod2(0,X,Y)优雅的终止......



Answer 2:

第一个问题(为什么),是很容易被发现,特别是如果知道左递归 。 sum(A,B,C) 结合当C 结合 A和B,但原始程序PROD(A,B,C)不使用绑定,以及不是与静止A,B未结合的递归。

如果我们换总和,督促我们从总和递归调用2个有用的绑定:

sum(M, K, P)

现在,M是装订成册,将用于终止左递归。 我们可以换N和M,因为我们知道,产品是可交换的。

sum(0, M, M).
sum(s(N), M, s(K)) :-
    sum(N, M, K).

prod3(0, _, 0).
prod3(s(N), M, P) :-
    sum(M, K, P),
    prod3(M, N, K).

需要注意的是,如果我们换M,K(即总和(K,M,P)),当prod3被称为以P未知,我们再有一个非终止循环,但总和。

?- prod3(X,Y,s(s(s(s(s(s(0))))))).
X = s(s(s(s(s(s(0)))))),
Y = s(0) ;
X = s(s(s(0))),
Y = s(s(0)) ;
X = s(s(0)),
Y = s(s(s(0))) ;
X = s(0),
Y = s(s(s(s(s(s(0)))))) ;
false.

OT我被CTI困惑报告:prod3(A,B,C)terminates_if B(A),B(B); B(A),B(C)。



文章来源: Prolog successor notation yields incomplete result and infinite loop