如何通过序言使用SUCC递归查询运行?(How does prolog run through re

2019-09-16 18:02发布

谁能给我解释一下为什么这个序言查询的工作方式是这样。 该定义是:

add(0,Y,Y). 
add(succ(X),Y,succ(Z)):- add(X,Y,Z).

鉴于这种:

?-  add(succ(succ(succ(0))),  succ(succ(0)),  R).

继承人的查询跟踪:

Call:  (6)  add(succ(succ(succ(0))),  succ(succ(0)),  R) 

Call:  (7)  add(succ(succ(0)),  succ(succ(0)),  _G648) 

Call:  (8)  add(succ(0),  succ(succ(0)),  _G650) 

Call:  (9)  add(0,  succ(succ(0)),  _G652) 

Exit:  (9)  add(0,  succ(succ(0)),  succ(succ(0))) 

Exit:  (8)  add(succ(0),  succ(succ(0)),  succ(succ(succ(0)))) 

Exit:  (7)  add(succ(succ(0)),  succ(succ(0)), 
                                              succ(succ(succ(succ(0))))) 

Exit:  (6)  add(succ(succ(succ(0))),  succ(succ(0)), 
                                                succ(succ(succ(succ(succ(0))))))

这混淆了我最有关教程中的一部分的事实是,在第一个参数,SUCC被剥离,并递归。 虽然递归不过,R斩获SUCC ...如何? 此外,哪里零来自在第一个出口(9)? 我是新来的Prolog,和我想了解一门功课的语言。 任何帮助非常赞赏。

注:对于任何有兴趣,链接到本教程是http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlse9

Answer 1:

“哪里零来自在第一个出口(9)?”

该呼叫add(0, succ(succ(0)), _G652)是统一与说,如果的第一个参数的第一条add为零,则第二和第三是相同的。 在这个特定的situatiob可变_G652变得succ(succ(0))

“虽然递归不过,R斩获SUCC ...如何?”

这是第二个条款的申请结果。 这一条款状态(大约)你先带succ从第一个参数,然后调用add递归,最后,添加其他的“层” succ从这个递归调用回来的第三个参数。

谓词add不过是一个直接的实现除了在皮亚诺算术的: http://en.wikipedia.org/wiki/Peano_axioms#Addition



Answer 2:

你看, callexitverbs ,行动的解释采取试图解决您提出的查询。 然后,跟踪暴露了做实际工作的细节,并且让你在历史的角度查看。

当Prolog的必然选择一个规则( call ),它使用的name ,你给它(所谓的functor ),并试图以unify的规则的头上,每种说法。 然后,我们通常说的序言还考虑了arity ,即数量的参数,以供选择。

Unification试图将“使等于”两个词,而值得一提的结果所谓的bindings变量。 你已经知道的变量是那些刚开始的名字Uppercase 。 这样的名称识别规则未定值,即是placeholders的参数。 为了避免混淆,当Prolog的显示的痕迹,变量被重命名,使我们能够识别他们,因为相关细节它的identities证明期间建立或绑定。

然后你看到这样_G648在跟踪符号。 他们停留的所谓目标,即尚未被实例化的参数RZ 。 R是唯一的(只发生在顶层调用),所以这段序言亲切保持用户友好的名称,但ž来自程序,可能会发生多次,然后得到了重新命名。

要回答这个查询

?-  add(succ(succ(succ(0))),  succ(succ(0)),  R).

序言首先尝试匹配

add(0,Y,Y). 

和失败,因为SUCC(SUCC(SUCC(0))不能进行等于0。然后尝试

add(succ(X),Y,succ(Z)) :- add(X,Y,Z).

因此必须解决这些绑定(向左呼叫者”而言):

succ(succ(succ(0))) = succ(X)
succ(succ(0)) = Y
R = Z

你可以看到为什么X变得succ(succ(0))我们有一个新的目标来证明,即规则主体add(X,Y,Z)与刚刚建立的绑定:

添加(SUCC(SUCC(0)),SUCC(SUCC(0)),_ G648)

等等......直到X成为0和目标匹配

add(0,Y,Y).

然后Y变成SUCC(SUCC(0)),并且值得一提的还给出一个值Z在调用规则。

HTH



Answer 3:

将有更多的注释(希望)更清晰的轨迹:

 (6) Call:  add(succ(succ(succ(0))),  succ(succ(0)),  R)          % R     = succ(_G648)
      (7) Call:  add(succ(succ(0)),  succ(succ(0)),  _G648)       % _G648 = succ(_G650) 
           (8) Call:  add(succ(0),  succ(succ(0)),  _G650)        % _G650 = succ(_G652) 
                (9) Call:  add(0,  succ(succ(0)),  _G652)         % _G652 = succ(succ(0))
                (9) Exit:  add(0,  succ(succ(0)),  succ(succ(0)))       
           (8) Exit:  add(succ(0),  succ(succ(0)),  succ(succ(succ(0)))) 
      (7) Exit:  add(succ(succ(0)),  succ(succ(0)), succ(succ(succ(succ(0))))) 
 (6) Exit:  add(succ(succ(succ(0))),  succ(succ(0)), succ(succ(succ(succ(succ(0))))))

正如你所看到的,四个出口是多余的,最终的答案在点已经知道 (9) Exit ; 只有一个出口是足够的在这一点上:

     %     R = succ(_G648)
     %              _G648 = succ(_G650) 
     %                           _G650 = succ(_G652) 
     %                                        _G652 = succ(succ(0))
     % thus,
     %     R = succ(        succ(        succ(        succ(succ(0)) )))

这的确是尾调用优化下会发生什么,作谓语的定义的确尾递归并根据结果R是建立在一个自上而下的方式,有逐渐被逻辑变量的实例化充满了“洞”。 所以succ( _ )不递归调用增加,但其成立。 这也是尾递归模利弊优化的精髓。



文章来源: How does prolog run through recursive queries using succ?