首先,\+
是对目标的否定。当它后面的目标失败时,它就成功了。例如:
?- member(3, [1,2,3]). # 3 is a member of the List
true.
?- member(4, [1,2,3]). # 4 is not a member
false.
?- \+member(4, [1,2,3]). # succeeds, because 'member' fails
true.
?- \+member(3, [1,2,3]).
false.
?- atom_chars('hi', C).
C = [h, i].
?- atom_chars('hi', [h, i]).
true.
?- atom_chars('hello', [h, i]).
false.
?- \+atom_chars('hello', [h, i]).
true.
其次,累加器是一种通过递归线程化状态的方式,以利用尾递归优化。
考虑这两种计算阶乘的等效方法:
?- [user].
|: fact_simple(0, 1).
|: fact_simple(N, F) :-
N1 is N-1,
fact_simple(N1, F1),
F is N*F1.
|: % user://2 compiled 0.00 sec, 440 bytes
true.
?- fact_simple(6, F).
F = 720 .
[user].
|: fact_acc(N, F) :- fact_acc(N, 1, F).
|: fact_acc(0, Acc, Acc).
|: fact_acc(N, Acc0, F) :-
N1 is N-1,
Acc is Acc0 * N,
fact_acc(N1, Acc, F).
|: % user://4 compiled 0.00 sec, 1,912 bytes
true.
?- fact_acc(6, F).
F = 720 .
第一个版本只是在递归中调用自己,等待子调用完成。只有这样,它才会将它N
的 -value 与子调用的结果相乘。
第二个版本使用了一个累加器(Acc
)。请注意,这1
不是累加器,而是初始值。之后,对谓词的每次调用都会将它的N
-value 与累加器相乘,当递归到达它的基本情况时,累加器的值已经是最终值。
问题真的不是‘累加器可以是什么?(0或空列表或任何东西)。这只是一种“随手”累积值的方式,并且永远不会返回调用谓词。这样,Prolog 系统就不必建立一个不断增长的调用堆栈。
但是请注意,在此示例中,乘法的顺序自然是相反的。乘法无关紧要,但对于其他值(如列表),必须注意这一点。
fact_simple
将乘法作为1 * 2 * 3 * 4 * 5 * 6
,而fact_acc
将其作为1 * 6 * 5 * 4 * 3 * 2
。如果不清楚,只需对两者都进行跟踪!