递归程序说明

时间:2014-03-05 01:48:23

标签: prolog factorial

所以我在Prolog中有以下工作代码,它产生给定值A的阶乘:

factorial(0,1).
factorial(A,B) :- A>0, C is A-1, factorial(C,D), B is A*D.

我正在寻找有关此代码如何工作的解释。即,当您询问查询时会发生什么:factorial(4,Answer)。

首先,

factorial(0, 1).

我知道上面是递归定义的“基本情况”。我不知道为什么/如何是基本情况。我的猜测是factorial(0,1)插入一些包含(0,1)的结构作为“factorial”的成员。如果是这样,结构是什么样的?我知道如果我们说“雨天(西雅图)”,这意味着西雅图下雨了。但是“阶乘(0,1)”...... 0,1是阶乘?我意识到它意味着0的阶乘是1,但是从长远来看这是如何使用的呢? (写这篇文章有助于我了解更多信息,但我希望得到一些反馈,以确保我的想法是正确的。)

factorial(A,B) :- A>0, C is A-1, factorial(C,D), B is A*D.

现在,上面的代码究竟是什么意思。我该怎么看?

我正在读它:如果A> 0,C是A-1,阶乘(C,D),B是A * D,则(A,B)的阶乘为真。这对我来说听起来不太对劲......是吗?

“A> 0”。所以如果A等于0,会发生什么?它不能在此时返回,否则永远不会使用基本情况。所以我的猜测是A> 0返回false,但其他函数最后一次执行。递归是否因为达到基本情况而停止,或者因为A不大于0?或两者兼而有之?在什么时候使用了基本情况?

我想这可以归结为一个问题:同时拥有一个基本案例和A>的目的是什么? 0?

抱歉问题很糟糕,谢谢。

编辑:事实上,我从程序中删除了“A> 0”,代码仍然有效。所以我想我的问题至少不是愚蠢的。 (该代码来自教程。)

3 个答案:

答案 0 :(得分:2)

在数据结构方面考虑Prolog事实和规则会适得其反。当你写factorial(0, 1).时,你向Prolog解释者断言一个被认为是普遍正确的事实。仅凭这一事实,Prolog可以回答三种类型的问题:

  • 0的阶乘是什么? (即factorial(0, X);答案为X=1
  • 1是什么数字的阶乘? (即factorial(X,1);答案为X=0
  • 0的阶乘是1是真的吗? (即factorial(0,1);答案为“是”)

就您的Prolog计划的其余部分而言,只有第一个问题很重要。这是factorial/2规则的第二个条款在评估factorial时将会询问的问题。

第二条规则使用逗号运算符,这是Prolog说“和”的方式。您的解释可以按照变量AB重写,如下所示:

  当B A A>0设置为C时,{p> A-1D的阶乘,而C设置为阶乘BA设置为DA

此规则涵盖高于零的所有factorial(C,D)。对C的引用会一次又一次地使用相同的规则,直到1到达零。这是当此规则停止适用时,因此Prolog将获取“基本案例”规则,并使用factorial(C, D)作为其输出。此时,评估factorial/2的链开始展开,直到它一直到规则的初始调用。这是Prolog计算最终答案的时候,A>0返回“是”并产生所需的输出值。

为了响应您的修改,删除factorial/2并不危险,只有获得第一个结果。通常,您可以要求Prolog找到更多结果。这是删除了A>0的{​​{1}}会失败的原因,因为它会以负数开始沿着第二个子句的调用链 - 一系列调用将以数字溢出或堆栈溢出结束,以先到者为准。

答案 1 :(得分:1)

如果您来自过程语言背景,则以下C ++代码可能有所帮助。它非常准确地反映了Prolog代码的执行方式(至少对于给出A和B未实例化的常见情况):

bool fac(int a, int &b)
{
    int c,d;
    return
        a==0  &&  (b=1,true)
        ||
        a>0  &&  (c=a-1,true)  &&  fac(c,d)  &&  (b=a*d,true);
}

Prolog逗号的操作类似于顺序&&,而多个子句类似于顺序||

答案 2 :(得分:1)

我对prolog如何工作的心智模型是树遍历。

prolog数据库中的事实和谓词构成了树的 forest 。当您要求Prolog引擎评估谓词时:

?- factorial(6,N).

Prolog引擎查找以指定的仿函数和arity为根的树(在本例中为factorial/2)。然后Prolog引擎执行该树的深度优先遍历,试图使用统一和模式匹配找到解决方案。事实按照原样进行评估;对于谓词,将评估:-运算符的右侧,在各种逻辑运算符的引导下进一步进入树。

评估在第一次成功评估树中的叶节点时停止,prolog引擎在树遍历中记住其状态。在回溯时,树遍历从它停止的地方继续。当树遍历完成且没有更多路径可以遵循时,执行最终完成。

这就是为什么Prolog是一种描述性语言而不是命令式语言:你描述什么是真理(或虚假),让Prolog引擎弄清楚如何到达那里。