所以我在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”,代码仍然有效。所以我想我的问题至少不是愚蠢的。 (该代码来自教程。)
答案 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说“和”的方式。您的解释可以按照变量A
和B
重写,如下所示:
当B
A
A>0
设置为C
时,{p>A-1
是D
的阶乘,而C
设置为阶乘B
,A
设置为D
次A
此规则涵盖高于零的所有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引擎弄清楚如何到达那里。