我有一个阶乘谓词fact(N,F)
,其中N
或F
或两者都绑定到一个数字。
例如,我可以有fact(3,F)
或fact(N,6)
。
这是我的谓词,它能够工作但我并不真正理解它的原理。我使用了trace
,但仍然有困惑。
fact(0,1).
fact(N,F) :-
fact(N1,F1),
N is N1 + 1,
F is N * F1.
我有一个阶乘谓词fact(N,F)
,其中N
或F
或两者都绑定到一个数字。
例如,我可以有fact(3,F)
或fact(N,6)
。
这是我的谓词,它能够工作但我并不真正理解它的原理。我使用了trace
,但仍然有困惑。
fact(0,1).
fact(N,F) :-
fact(N1,F1),
N is N1 + 1,
F is N * F1.
这个片段什么时候会终止?看看剩下的可见部分!fact(0,1) :- false. fact(N,F) :- fact(N1,F1), false,N is N1 + 1,F is N * F1.
N
只在头部出现一次:没有人关心第一个参数!F
也是如此。因此,无论你有什么参数,这个程序都不会终止。因此,对于您的原始程序也是如此!
在原始版本中,这并不那么清楚。注意:?- fact(29,F).
F = 8841761993739701954543616000000
起初看起来很好,但如果你要求下一个答案(使用空格或;
),你会陷入循环中,即等待永远不会到来的答案。更糟糕的是,错误的查询会立即进入循环:
?- fact(29,1).
loops.
那么,如果你不了解具体情况,如何找到这些问题呢?这就是 false
的作用。一个永远不为真的目标。如果你像这样添加它 fact(29,F), false.
你将不会被美丽的答案分心。
为什么把所有的算术都放在最后呢?我怀疑是因为之前出现了一些错误。有一个简单的方法可以避免所有这样的错误:
:- use_module(library(clpfd)).
现在你可以使用#=
代替is
,并且需要一些限制,比如N #>= 1
。我可以离开你吗?
L = [_E]
。它需要一些量化。等等。 - false
fact(3, F)
与fact(0, 1)
不匹配(因为3和0不能统一),所以Prolog将使用下一个子句fact(N, F)
与N = 3
进行匹配。然后,它再次调用fact(N1, F1)
,根据第一个子句得出N1 = 0
和F1 = 1
,依此类推。请注意,在找到解决方案后,它会尝试查找更多解决方案而不终止,导致堆栈溢出。 - lurkerfactorial(0, 1). factorial(N, F):- N > 0, N1 is N - 1, factorial(N1, F1), F is N * F1.
,一直尝试直到得到了结果。 - zaig