我是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.
有人可以解释一下吗?
答案 0 :(得分:4)
问题是prolog主要使用统一来进行计算。要让它进行算术运算,您需要告诉它使用is
运算符明确地执行此操作。
因此,在您的第一个程序中,您明确告诉它使用N1 is N - 1
子句执行减法,以便按预期工作。
但是在你的第二个程序中,当你写fact(N - 1, R1)
时,你不是要求算术计算,而是要求统一。
如果我定义了fact(5 - 1, foo).
这个事实,那么我可以查询?- fact(N - 1, Y), write([N, Y]).
,prolog会很高兴地将N
与5
和Y
统一起来foo
1}}。此查询将输出[5, foo]
。
所以,更进一步,如果我有事实fact(foo - bar).
,那么查询?- fact(X - Y), write([X, Y]).
将很乐意统一并返回[foo, bar]
。 -
不表示减法 - 它是所表示事实结构的一部分。
答案 1 :(得分:2)
当传递算术表达式(而不是数字)时,您需要在某些时间评估表达式。
(>)/2
之类的算术运算符会自动执行此操作,因此目标1 > (0+0)
会成功,就像1 > 0
一样。
隐式统一(在子句头中)和与(=)/2
目标的明确统一表达了任意 Prolog术语的相等性,而不仅仅是算术表达式。所以目标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).
:)