知识库递归另外在Prolog中
add(0,Y,Y). // clause 1
add(succ(X),Y,succ(Z)) :- add(X,Y,Z). // clause 2
查询
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))))))
我的问题
- 我看到如何在第递归调用2条的最外SUCC() 在每个呼叫对参数1.
- 我看看它是如何在增加了一个外SUCC()以3参数每次通话。
- 我看到当第一个参数作为这些递归调用 的结果达到0.此时,我看到1st子句如何将第二个参数 复制到第三个参数。
这是我困惑的地方。
一旦执行第1条款,并在第2条自动 得到执行为好,然后加入SUCC()第一个参数?
另外,程序如何终止,为什么它不会仅仅保持 无限地为第一个和第三个参数添加succ()?
从LearnPrologNow.com解释(我不知道)
让我们通过使用方式的Prolog来处理这个查询走一步看一步。下面给出了查询的跟踪和搜索树的 。
第一个参数不是0,这意味着只能使用add/3的第二个子句 。这导致递归调用add/3。将 最外面的succ函数从原始查询 的第一个参数中删除,结果将成为递归查询的第一个参数。第二个参数不变地传递给 递归查询,递归查询的第三个参数是一个 变量,下面给出的跟踪中的内部变量_G648。注意 _G648尚未实例化。但是它与R (我们用作原始 查询中的第三个参数的变量)共享值,因为当查询是 与第二个子句的头部统一时,R被实例化为succ(_G648)。但这意味着R是 不再是一个完全没有实际意义的变量。现在它是一个复杂的 术语,它有一个(未被证实的)变量作为它的参数。
接下来的两个步骤基本相同。随着每一步的第一个参数变成一个succ小一层;下面给出的跟踪和 搜索树都很好地显示了这一点。与此同时,在每一步都会向R添加一个仿函数,但始终将最内层的变量 变为无实际意义。在第一次递归调用R之后是 succ(_G648)。在第二次递归调用之后,_G648被succ(_G650)实例化为 ,所以R是succ(succ(_G650)。在第三次递归调用之后,_G650被succ(_G652)实例化并且因此 变为succ(succ (SUCC(_G652)))。搜索树显示这一步 一步实例。
在这个阶段,所有SUCC函子已经被扒掉第一 参数,我们可以应用基本条款。第三个参数是 等同于第二个参数,因此复数项R中的'hole'(未示例的 变量)最终被填充,并且我们通过。
感谢您花时间回答我的问题,并提供比本书更好的解释。 – prolog
非常欢迎您!正如我所看到的那样,Prolog的一个主要吸引力是我们*不必*以这种痛苦的方式来调试我们的程序。相反,我们可以基于程序的声明性属性应用更强大的调试方法,并通过应用逻辑推理非常快速地缩小代码中的错误。跟踪只会导致您远离语言的真正威力和普遍性,迫使您在特定的使用方向上阅读您的代码。请参阅我的个人资料页面,了解我希望能帮助您学习Prolog的资源。请享用! – mat
也许我最大的问题之一来自纯粹的程序编程背景。我看到了您的个人资料中的链接,我想知道为什么他们在Google中的排名不如LearnPrologNow:D – prolog