私はこのような事実のデータベースを持っています:
li(a,2).
li(b,3).
li(b,1).
li(c,2).
li(d,1).
li(d,1).
複数のファクトli(Let、_)が存在する場合に成功する述語more(+ Let)を記述する必要があります。
たとえば、クエリmore(b)とmore(d)は成功しますが、more(a)とmore(c)は成功しません。私の考えは、li(Let、_)が複数回成功するかどうかを確認することでしたが、その方法がわかりません。
私はこのような事実のデータベースを持っています:
li(a,2).
li(b,3).
li(b,1).
li(c,2).
li(d,1).
li(d,1).
複数のファクトli(Let、_)が存在する場合に成功する述語more(+ Let)を記述する必要があります。
たとえば、クエリmore(b)とmore(d)は成功しますが、more(a)とmore(c)は成功しません。私の考えは、li(Let、_)が複数回成功するかどうかを確認することでしたが、その方法がわかりません。
試してみてくださいfindall/3
:
findall(X, li(d,X), L), length(L,N), N>1.
アウトを抽象化しd
て述語を作成するのは簡単です。右?:)
のような述語を使用したくない場合はfindall
、知識の表現を変更できます。つまり、知識を1レベル下げます。
my_knowledge(li, [a-2,b-3,b-1,c-2,d-1,d-1]).
次に、SWIPrologの述語select/3
を使用してそれを処理できます。
select_knowledge(kn, key, R):-
my_knowledge(kn,L),
select_key(L,key,R).
select_key(L,K,R):-
select(K-X,L,L1) -> R=[X|R1], select_key(L1,K,R1)
; R = [].
最後の述語をリストの基本的な再帰として書き直し、最初のN個の結果を取得した後に停止するように微調整できます。
more_than_once(Goal) :-
\+ \+ call_nth(Goal,2).
この回答call_nth/2
で定義されているように。
提案された他のソリューションと比較したこのソリューションの大きな利点は、回答のシーケンスが非常に多い場合でも、迅速に成功することです。実際、それは答えの無限のシーケンスに対してさえ成功します:
?-more_than_once(repeat)。 本当。 ?-more_than_once(between(1,100000、_))。 本当。
(の実装でcall_nth/2
は、SWIの非標準の低レベルの組み込みが使用されます。これを回避することは可能ですが、さらに頭痛の種になります。)
SWI-Prologにはlibrary(aggregate)があります。
:- [library(aggregate)].
more(Key) :- aggregate_all(count, li(Key, _), C), C > 1.
テスト:
?- more(b).
true.
?- more(a).
false.
習得するのは簡単ではありませんが、そのような一般的なタスクを処理するのに役立ちます。コードベースが非常に大きい場合、findall(および内部でfindallを使用する集約も)は非効率的であり、その要素をカウントするためだけにリストを作成する可能性があります。
次に、副作用ベースの述語を使用できます。この関連する回答には、そのようなユーティリティがあります。最大の効率については、コメントを参照してください。ここでは、nb_setval /nb_getval...の使用方法が説明されています。