我是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.
有人可以解释一下吗?
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
统一。此查询将输出[5, foo]
。fact(foo - bar)
,那么查询?- fact(X - Y), write([X, Y])
将愉快地统一并返回[foo, bar]
。 -
不表示减法-它是所表示的事实结构的一部分。当传递算术表达式(而不是数字)时,需要在特定的时间求值表达式。
像(>)/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).
这样的查询:)
fact\2
的第二个版本以每次评估其第一个参数并解决第二个版本中的问题,但按照第一个版本所做的方式(在传递之前评估)更为常规。Prolog 管理参数的“惰性评估”的灵活性可能很有用,但阶乘计算太直接了,无法利用它。 - hardmathfact/3
)来使其工作。 - hardmath