宣言型演算を使用することで、これが機能するようになったことは素晴らしいことです。
あなたが得た解決策について、いくつかの小さな追加コメントがあります。
count(_, [], 0) :- !.
count(El, [El|T], N) :-
count(El, T, N1),
N #= N1 + 1。
count(El, [Y|T], N) :-
El \= Y,
count(El, T, N)。
チェック (リスト 1、リスト 2) :-
カウント(3、リスト1、M)、
カウント(2、リスト2、N)、
M #= N.
最初に、check/2
はコードのどこにも使用されていないことに注意してください。そのため、以下ではその定義を省略します。
最も一般的なクエリ
私が何も知らない Prolog コードを確認するときは、すべての引数が変数である最も一般的なクエリを常に最初に試します。理想的には、答えは一般的な解決策を示してくれます。
たとえば、あなたの場合:
?- カウント (E、Ls、C)。
Ls = []、
C = 0 .
これは、誤って、述語の解が1 つしかないことを示しています。これは明らかに意図したものではありません。
したがって、最初のステップとして、 を削除して!/0
、このコードを次のように変更することをお勧めします。
カウント (_、[]、0)。
count(El, [El|T], N) :-
count(El, T, N1),
N #= N1 + 1。
count(El, [Y|T], N) :-
El \= Y,
count(El, T, N)。
この変更を適用すると、次のようになります。
?- カウント (E、Ls、C)。
Ls = []、
C = 0;
Ls = [E]、
C = 1;
Ls = [E, E],
C = 2;
Ls = [E, E, E],
C = 3 .
これははるかに良く見えます。現在、いくつかの有効な答えが得られています。
終了
この述語からいくつの答えが得られるでしょうか? 特に、答えは有限個しかないのですか?その場合、次のクエリが終了すると予想されます。
?- count(E, Ls, C), false .
試してみて、実際に終了しないことを確認してください(少なくともすぐには終了しません)。の正しい実装から、最も一般的なケースで非終了が期待されるため、これは良い兆候です!count/3
完全
理想的には、述語が完全であることを望みます:有効な答えを省略すべきではありません。
例えば:
?- count(E, [X,Y,Z], C)。
E = X、X = Y、Y = Z、
C = 3 ;
間違い。
これらは本当にすべてのソリューションですか?私はそうは思わない!確かに とは異なる長さ 3 のリストがあります [E,E,E]
。
実際、あなたのプログラムはある意味でそれらについても「知っています」:
?- count(E, [1,2,3], C)。
E = C、C = 1 ;
間違い。
しかし、繰り返しになりますが、これらはすべてのケースではありません。E
1と異なる答えはどこにありますか?
非単調 (\=)/2
述語を使用しているため、これらの問題に直面しています。これには、特に現在 Prolog を学習し始めたばかりの場合、理解するのが非常に難しいプロパティがいくつかあります。例えば:
?- X \= Y、XY = ab.
偽。
?- XY = ab、X \= Y.
X = a、
Y = b .
次のバージョンを取得して、2 つの用語が異なることを示すために代わりに使用するdif/2
ことをお勧めします。
カウント (_、[]、0)。
count(El, [El|T], N) :-
count(El, T, N1),
N #= N1 + 1。
count(El, [Y|T], N) :-
dif(El, Y),
count(El, T, N)。
このバージョンでは、次のようになります。
?- count(E, [X,Y,Z], C)。
E = X、X = Y、Y = Z、
C = 3;
E = X、X = Y、
C = 2、
差分 (Y, Z) ;
E = X、X = Z、
C = 2、
差(Z、Y) ;
等
そして、特に:
?- count(E, [1,2,3], C)。
E = C、C = 1 ;
E = 2、
C = 1;
E = 3、
C = 1;
C = 0、
差分(E, 3),
差分(E, 2),
dif(E, 1) .
これにより、発生する可能性のあるすべてのケースがカバーされます。
公正な列挙
述語は純粋で単調なので、反復的な深化によって答えを公平に列挙するために使用できます。
例えば:
?- 長さ (Ls、_)、カウント (E、Ls、C)。
Ls = []、
C = 0;
Ls = [E]、
C = 1;
Ls = [_G588]、
C = 0、
dif(E, _G588) ;
Ls = [E, E],
C = 2;
Ls = [E, _G597],
C = 1、
dif(E, _G597) .
C = 2 ;
等
これはとてもいいことで、これを真の関係として、カウントだけでなく、生成にも使用できることを示しています。
したがって、この述語が一般的に何を意味するかをより適切に説明する述語名を検討することができます。これは演習として残します。
末尾再帰バージョン
純粋な述語を使用しているため、目標を自由に並べ替えて、述語の末尾を recursiveにすることができ、次の結果が得られることに注意してください。
カウント (_、[]、0)。
count(El, [El|T], N) :-
N #= N1 + 1、
count(El, T, N1).
count(El, [Y|T], N) :-
dif(El, Y),
count(El, T, N)。
決定論
現在、たとえば次のようなものがあります。
?- count(a, [a,a,a], Cs)。
Cs = 3 ;
偽。
を使用すると、この述語の決定if_/3
性を改善できます。
:- use_module(ライブラリ (reif) )。
カウント (_、[]、0)。
count(E, [L|Ls], N) :-
if_ (E=L, N #= N1 + 1, N #= N1),
カウント (E、Ls、N1)。
これにより、述語は少なくともインデックス作成に適したものになります。このような場合に決定論を改善するかどうかは、Prolog システムのインデックス作成メカニズムによって異なります。