Recursion 为什么递归函数在调用外部谓词时会失败,从而使其成功?

Recursion 为什么递归函数在调用外部谓词时会失败,从而使其成功?,recursion,prolog,Recursion,Prolog,我在写一个阶乘函数的实现。但我不太清楚我的方法失败的原因: factorial(0,1). factorial(N,F) :- X is div(F,N), factorial(N-1,X). 我给它一个测试用例: ?- factorial(1,1). true 但是它给了我一个0除的错误。当这个函数达到这个值时,为什么它不回到析因(0,1)的定义,我怎样才能确保它是这样的呢?N-1是一个术语而不是一个数字 您希望定义 factorial(N,F) :- X is d

我在写一个阶乘函数的实现。但我不太清楚我的方法失败的原因:

factorial(0,1).
factorial(N,F) :-
    X is div(F,N),
    factorial(N-1,X).
我给它一个测试用例:

?- factorial(1,1).
true

但是它给了我一个0除的错误。当这个函数达到这个值时,为什么它不回到析因(0,1)的定义,我怎样才能确保它是这样的呢?

N-1
是一个术语而不是一个数字

您希望定义

factorial(N,F) :-
    X is div(F,N),
    N1 is N - 1,
    factorial(N1,X).
如果跟踪原始代码的执行情况,您会立即看到这一点

?- trace,factorial(1,1),notrace.
   Call: (8) factorial(1, 1) ? creep
   Call: (9) _G1063 is 1 div 1 ? creep
   Exit: (9) 1 is 1 div 1 ? creep
   Call: (9) factorial(1-1, 1) ? creep
   Call: (10) _G1069 is 1 div (1-1) ? creep
ERROR: div/2: Arithmetic: evaluation error: `zero_divisor'
术语
1-1
0
不统一,因此解释者求助于第二个从句

如果
N1为N-1
,则跟踪看起来与您预期的一样

?- trace,factorial(1,1),notrace.
   Call: (8) factorial(1, 1) ? creep
   Call: (9) _G2133 is 1 div 1 ? creep
   Exit: (9) 1 is 1 div 1 ? creep
   Call: (9) _G2136 is 1+ -1 ? creep
   Exit: (9) 0 is 1+ -1 ? creep
   Call: (9) factorial(0, 1) ? creep
   Exit: (9) factorial(0, 1) ? creep
   Exit: (8) factorial(1, 1) ? creep
true .
要使
factorial(0,3)
的阶乘失败,可以在main子句中添加一个类似
N>0的保护谓词

factorial(N,F) :-
    N > 0,
    X is div(F,N),
    N1 is N - 1,
    factorial(N1,X).
还有一些改进 这不是一个非常有用的谓词,因为它需要绑定两个参数,如果其中一个是变量,则会失败。在Prolog表示法中,它的签名是阶乘(+N,+F)

更有用的谓词应该有一个签名
阶乘(+N,?F)
。这可以通过以下定义来实现

factorial(0,1).
factorial(N,F):-
    N > 0,
    N1 is N -1, 
    factorial(N1,X),
    F is X * N.
然而,这个定义不是尾部递归的,我们被告知这样的定义不能有效地使用堆栈。我们需要随身携带一件行李 获取
阶乘(+N,?F)
的尾部递归定义的部分结果


谢谢,这很有道理。不过,我现在遇到了第二个问题,那就是我不知道如何确保
factorial(0,X)
为任何
X
不等于1的值返回false。您可以在main子句中添加一个类似
N>0
的保护谓词。
N>0
应该是该谓词子句中的必要条件。我不认为它是可选的。@ MITCHELFAAS,我完成了这篇文章,一直到“代码>阶乘< /C>谓词”的“规范”定义。
factorial(N,F):-factorial(N,1,F).
factorial(0,F,F).
factorial(N,X,F):-
    N>0,
    N1 is N - 1,
    X1 is X * N,
    factorial(N1,X1,F).