1

私はアキュムレータとは何か、そしてアキュムレータが何をするのかについてのチュートリアルを探していましたが、すべての説明は非常に複雑で、それを利用できるようにそれらがどのように機能するかについて十分に明確に理解できていません。アキュムレータは、他のコードによって呼び出されて変更される可能性のある数値などを保持していることを理解しているようです。問題は、アキュムレータとは何かを理解していて、いつ必要になるかはわかっているのに、実際にどのように使用するかがよくわからないことです。

私が見たチュートリアルから、アキュムレータが空のリストのように見えることもあれば、「0」のように見えることもあり、正確にアキュムレータと見なすことができるものとできないものについて疑問に思います。アキュムレータの使い方を簡単に説明してもらえますか?

また、私の質問の2番目の部分では、プロローグコードでこれを頻繁に使用している人々に気づいたようです。

\+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.

第二に、アキュムレータは、末尾再帰の最適化を利用するために、再帰を介して状態をスレッド化する方法です。

階乗を計算する次の2つの同等の方法を検討してください。

?- [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にサブコールの結果を乗算します。

2番目のバージョンでは、代わりにアキュムレータを使用しています(Acc)。1これはアキュムレータではありませんが、初期値であることに注意してください。その後、述語を呼び出すたびに、その値にアキュムレータが乗算さNれ、再帰がベースケースに達すると、アキュムレータの値はすでに最終値になっています。

問題は実際にはそうではありません'アキュムレータは何ができるのでしょうか?(0または空のリストなど)。これは、「必要に応じて」値を累積する方法にすぎず、呼び出し元の述語に戻ることはありません。このように、Prologシステムは増え続けるコールスタックを構築する必要はありません。

ただし、この例では、乗算の順序が自然に逆になっていることに注意してください。乗算は重要ではありませんが、他の値(リストなど)の場合は、それを処理する必要があります。

fact_simpleとして乗算を行いましたが、1 * 2 * 3 * 4 * 5 * 6としてfact_acc持っていました1 * 6 * 5 * 4 * 3 * 2。それが不明な場合は、両方のトレースを実行してください。

于 2012-01-14T17:41:09.570 に答える