计算阶乘的Prolog代码

计算阶乘的Prolog代码,prolog,factorial,Prolog,Factorial,我不熟悉Prolog,我正在尝试编写一段代码来计算数字的阶乘。 此代码工作正常: fact(0,1). fact(N, R) :- N > 0, N1 is N - 1, fact(N1, R1), R is R1 * N. 但这一条没有: fact(0, 1). fact(N, R) :- N > 0, fact(N - 1, R1), R is R1 * N. 有人能解释一下吗?问题是prolog主要使用统一来进行计算。要让它进行算术运算,您需要使用is操作符明确地告诉它这样

我不熟悉Prolog,我正在尝试编写一段代码来计算数字的阶乘。 此代码工作正常:

fact(0,1).
fact(N, R) :- N > 0, N1 is N - 1, fact(N1, R1), R is R1 * N.
但这一条没有:

fact(0, 1).
fact(N, R) :- N > 0, fact(N - 1, R1), R is R1 * N.

有人能解释一下吗?

问题是prolog主要使用统一来进行计算。要让它进行算术运算,您需要使用
is
操作符明确地告诉它这样做

因此,在您的第一个程序中,您明确地告诉它使用子句
N1是N-1
,执行减法,这样就可以按预期工作

但在第二个程序中,当您编写
fact(N-1,R1)
时,您并不是在要求算术计算,而是要求统一

如果我定义了事实
fact(5-1,foo)。
那么我可以查询
?-fact(N-1,Y),编写([N,Y])。
和prolog会很高兴地将
N
5
Y
foo
统一起来。此查询将输出
[5,foo]


因此,更进一步,如果我有事实
fact(foo-bar)。
那么查询
?-fact(X-Y),write([X,Y])。
会很高兴地统一并返回
[foo,bar]
-
不表示减法-它是所表示事实结构的一部分。

当传递算术表达式(而不是数字)时,需要在特定时间对表达式求值

(>)/2这样的算术运算符会自动执行该操作,因此目标
1>(0+0)
会成功,就像
1>0
一样

隐式统一(在子句头中)和显式统一与
(=)/2
目标表示任意序言项的相等,而不仅仅是算术表达式。因此,目标
0=0
成功,但
0=(1-1)
失败

使用算术等式
(=:=)/2
0=:=0
0=:=(1-1)
都成功


fact/2
的第二个定义中,您可以通过编写
fact(N,1):-N=:=0.
而不是
fact(0,1)。
使第一个子句更一般。作为额外的好处,您可以运行类似于
?-fact(5+5,F)的查询。
:)

您可以重写
fact\2
的第二个版本,以便每次计算它的第一个参数,并在第二个版本中绕过问题,但在第一个版本中这样做更为常规(在通过之前进行计算)。Prolog管理参数“惰性评估”的灵活性可能很有用,但阶乘计算过于简单,无法利用它。一个挑战是将任一版本重写为尾部递归(符合最后一次调用优化的条件)。通常需要引入额外的参数(例如,
fact/3
)来实现这一点。