首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >prolog如何使用succ遍历递归查询?

prolog如何使用succ遍历递归查询?
EN

Stack Overflow用户
提问于 2012-04-25 10:23:22
回答 2查看 1.5K关注 0票数 5

有人能给我解释一下为什么这个prolog查询是这样工作的吗?它的定义是:

代码语言:javascript
复制
add(0,Y,Y). 
add(succ(X),Y,succ(Z)):- add(X,Y,Z).

考虑到这一点:

代码语言:javascript
复制
?-  add(succ(succ(succ(0))),  succ(succ(0)),  R).

下面是查询的跟踪:

代码语言:javascript
复制
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获得了一个成功的.怎么做?!另外,在第一个出口(9),零从哪里来?我是prolog的新手,我正在尝试理解这门语言作为家庭作业。任何帮助都非常感谢。

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

EN

回答 2

Stack Overflow用户

发布于 2012-04-25 14:37:19

然后,跟踪将显示已完成的实际工作的详细信息,并允许您从历史的角度查看它。

当Prolog必须选择一个规则(一个call)时,它会使用您给它的name (所谓的functor),并尝试unify规则头部中的每个参数。然后我们通常说,Prolog还考虑了arity,即参数的数量,用于选择。

Unification试图“使相等”两项,值得注意的结果是所谓的变量的bindings。您已经知道变量是以Uppercase开头的那些名称。这样的名称标识规则中的未指定值,即参数为placeholders。为了避免混淆,当Prolog显示轨迹时,变量会被重命名,这样我们就可以识别它们,因为相关的细节是在证明过程中建立的identities或绑定。

然后,您可以在trace中看到这样的_G648符号。R是唯一的(只在顶层调用中出现),所以这个Prolog友好地保留了用户友好的名称,但Z来自程序,可能会出现多次,然后被重命名。

回答这个问题

代码语言:javascript
复制
?-  add(succ(succ(succ(0))),  succ(succ(0)),  R).

Prolog首先尝试匹配

代码语言:javascript
复制
add(0,Y,Y). 

并且失败,因为succ( 0 ))不能等于0。然后尝试

代码语言:javascript
复制
add(succ(X),Y,succ(Z)) :- add(X,Y,Z).

因此,必须解决这些绑定(在调用者术语的左侧):

代码语言:javascript
复制
succ(succ(succ(0))) = succ(X)
succ(succ(0)) = Y
R = Z

你可以看到为什么X变成了succ(succ(0)),我们有一个新的目标要证明,也就是刚刚建立了绑定的规则主体add(X,Y,Z)

以此类推。直到X变为0并且目标匹配

add(0,Y,Y).

HTH

票数 4
EN

Stack Overflow用户

发布于 2018-05-31 21:19:48

代码语言:javascript
复制
 (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点上已经知道了;在这一点上只有一个出口就足够了:

代码语言:javascript
复制
     %     R = succ(_G648)
     %              _G648 = succ(_G650) 
     %                           _G650 = succ(_G652) 
     %                                        _G652 = succ(succ(0))
     % thus,
     %     R = succ(        succ(        succ(        succ(succ(0)) )))

这确实是在尾部调用优化下发生的事情,因为谓词定义确实是尾部递归的,并且R下的结果是以自顶向下的方式构建的,“洞”逐渐被逻辑变量的实例化所填补。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10308557

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档