首先,\+
是否定目标。它成功了,当它追随它的目标失败时。例如:
?- 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 .
第一个版本只是调用自身的递归,等待subcall完成。只有它的N
-value与subcall的结果相乘。
第二个版本使用累加器代替(Acc
)。请注意,1
不是累加器,而是初始值。之后,每次调用谓词时,都会将它的值与累加器相乘,并且当递归达到它的基本情况时,累加器的值已经是最终值。
这个问题真的不是'累加器可以做什么? (0或空列表或任何东西)。这只是一种积累价值的方式,“随你走”,永远不会回到调用谓词。这样,Prolog系统不必建立一个不断增长的调用堆栈。
但是请注意,在这个例子中,乘法的顺序自然是相反的。对乘法无关紧要,但对于其他值(如列表),则必须注意这一点。
fact_simple
做了乘法作为1 * 2 * 3 * 4 * 5 * 6
,而fact_acc
把它作为1 * 6 * 5 * 4 * 3 * 2
。如果不清楚,只需做一下两者的追踪!
谢谢,这有助于吨 – Arun22 2012-01-14 18:30:06
不客气。我只想补充说,累加器的'模式'并不是关于序言的具体情况,而是函数式编程的一个元素。 – firefrorefiddle 2012-01-15 08:13:15