カスタム述語が真である回数をカウントしたいと思います。たとえば、次のコードがあります。
is_man(john).
is_man(alex).
?:-is_man(X).
Xはjohnを返し、セミコロンを押すとalexを返し、falseを返します。
私は次のようなものを作りたいです:
count(is_man(X), Count).
そして、これは戻る
Count = 2
どうやってやるの?
SWI-Prologの場合:
aggregate_all(count, is_man(X), Count).
ISO標準のPrologソリューションの場合、findall/を使用してすべてのソリューションのリストを作成し、Countを結果のリストの長さに設定します。 findall/の最初の引数をフォームで作成する必要があるため、これをユーザー定義の述語count/2にラップするのは少し難しいかもしれません。 count/2の最初の引数として渡したいゴール内の自由な(バインドされていない)変数を考慮する方法。
多くのプロローグは、「カウンター」または他の形式の可変グローバル値を提供します。これは、非標準の拡張であり、障害駆動型「ループ」に関連して使用して、同じカウントを行うことができます。少し面倒ですが、Prolog標準の文字に固執する場合は、動的ファクトを調整して、独自の「カウンター」を作成するためにassertおよびretractを使用します。
後者のアプローチの例を以下に示します。 「マルチスレッドセーフ」にするには、追加のロジックが必要になります。
count(Goal,_) :-
setGoalCount(0),
call(Goal),
incGoalCount(1),
fail. /* or false in some Prologs */
count(_,Count) :-
getGoalCount(Count).
setGoalCount(_) :-
retract(getGoalCount(_)),
fail.
setGoalCount(X) :-
assert(getGoalCount(X)).
incGoalCount(Y) :-
retract(getGoalCount(X)),
!,
Z is X + Y,
assert(getGoalCount(Z)).
count(P,Count) :-
findall(1,P,L),
length(L,Count).