1

我一直在寻找关于什么是累加器以及它们的作用的教程,但是所有的解释似乎都非常复杂,并没有真正让我足够清楚地了解它们是如何工作的,以便我可以使用它。我似乎理解累加器会保留诸如数字之类的东西,然后可以被其他代码调用并更改。问题是虽然我了解什么是蓄能器并且知道何时需要它,但我不太确定如何实际使用它。

我的意思是从我看过的教程中,有时累加器似乎是一个空列表,而其他时候它似乎是“0”,这让我想知道究竟什么可以被认为是累加器,什么不能。有人可以简单地向我解释一下如何使用蓄电池吗?

同样对于我问题的第二部分,我似乎注意到人们在他们的序言代码中使用了很多:

\+member

我已经设法推断出它与列表有关,因为我总是看到它被用在对列表执行某些操作的代码行中,但是在四处搜索后我发现\+member实际上的意思是“否定为失败 - 不是可证明的”虽然我真的不明白这意味着什么,或者即使那个人是正确的。再次,有人可以向我解释一下究竟\+member是什么以及它可以用来做什么,同时试图保持你的解释简单,大词让我感到困惑。

4

1 回答 1

8

首先,\+是对目标的否定。当它后面的目标失败时,它就成功了。例如:

?- 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。如果不清楚,只需对两者都进行跟踪!

于 2012-01-14T17:41:09.570 回答