整数のリストを入力として受け取り、からの偶数要素を含むリストとからの奇数要素のリストのL
2つのリストを生成する述語を記述します。L
L
?- separate_parity([1,2,3,4,5,6], Es, Os).
Es = [2,4,6], Os = [1,3,5] ? ;
no
リストで構造的再帰を使用するだけです。相互に排他的な各ケースの同等性を書き留めます。
parity_partition([A|B], [A|X], Y):- 0 is A mod 2, parity_partition(B,X,Y).
parity_partition([A|B], X, [A|Y]):- 1 is A mod 2, parity_partition(B,X,Y).
parity_partition([],[],[]).
これは、関係parity_partition(L,E,O)
が成り立つことを意味します。
L=[A|B]
とA
偶数の場合 E=[A|X]
、O=Y
との関係parity_partition(B,X,Y)
が成り立ちます。L=[A|B]
、およびA
が奇数の場合 E=X
、、O=[A|Y]
および関係parity_partition(B,X,Y)
が成り立ちます。L=[]
、いつE=[]
、そしてO=[]
。これらの同等性を書き留めるだけで、これを解決するためのPrologプログラムが得られます。
運用上、これは次のことを意味します。リストを偶数のリストとオッズのリストに分割するL
にE
はO
、
1.`L`が空でないリスト`[A| B] `の場合、 1a。`A`が偶数の場合、 `E = [H | T]`に新しいリストノードを割り当て、 データフィールド`H=A`を設定します。 残りの入力リスト`B`を分離し続けます `T`と`O`に; また 1b。`A`が奇数の場合、 `O = [H | T]`に新しいリストノードを割り当て、 データフィールド`H=A`を設定します。 残りの入力リスト`B`を分離し続けます `E`と`T`に; また 2. `L`が空のリストの場合、`E`と`O`の両方を空のリストに設定します
実際の操作シーケンスは少し異なる場合がありますが、概念的には同じです。
1. L = [A | B]、E = [A|X]を統一してみてください。そうでない場合は、2に進みます。 1a。Aが偶数かどうかを確認します。 そうでない場合は、行われたインスタンス化を放棄します 統合の一部として、2に進みます。 1b。B、X、および同じOを続行します。BをLとして、XをEとして使用し、1に進みます。 2. L = [A | B]、O = [A|Y]を統一してみてください。そうでない場合は、3に進みます。 2a。Aが奇数かどうかを確認します。 そうでない場合は、行われたインスタンス化を放棄します 統合の一環として、3に進みます。 2b。B、Y、および同じEを続行します。BをLとして、YをOとして使用し、1に進みます。 3. L、E、Oを[]で統合します。
これにはclpfdを使用できます。このようにして、純粋な関係が得られます。
:- use_module(library(clpfd)).
list_evens_odds([], [], []).
list_evens_odds([E|Zs], [E|Es], Os) :-
0 #= E mod 2,
list_evens_odds(Zs, Es, Os).
list_evens_odds([E|Zs], Es, [E|Os]) :-
1 #= E mod 2,
list_evens_odds(Zs, Es, Os).
これを使用して、リストを偶数とオッズに分割するだけではありません。しかし、さらに先に進むことができます。次の相互作用はSWIとの相互作用ですが、SICStusでも同様になりasserta(clpfd:full_answer)
ます。
?-list_evens_odds([1、2、3、4、5、6]、Es、Os)。 Es = [2、4、6]、 Os = [1、3、5]; false。 ?-Zs = [A、B、C]、list_evens_odds(Zs、Es、Os)。 Zs = [A、B、C]、 Es = [A、B、C]、 Os = []、 mod 2#= 0、 B mod 2#= 0、 C mod 2#= 0; Zs = [A、B、C]、 Es = [A、B]、 Os = [C]、 mod 2#= 0、 B mod 2#= 0、 C mod 2#= 1; Zs = [A、B、C]、 Es = [A、C]、 Os = [B]、 mod 2#= 0、 B mod 2#= 1、 C mod 2#=0..。 ?-Es = [E]、Os = [O]、list_evens_odds(Zs、Es、Os)。 Es = [E]、 Os = [O]、 Zs = [E、O]、 E mod 2#= 0、 O mod 2#= 1; Es = [E]、 Os = [O]、 Zs = [O、E]、 E mod 2#= 0、 O mod 2#= 1; false。
EO
次はおそらく最も苛立たしいことです。ここでは、偶数と奇数の両方の整数があるかどうかを尋ねます。確かに、そのような整数は存在できません。しかし、それでも2つの答えが得られます。
?-EOs = [EO]、list_evens_odds(Zs、EOs、EOs)。 EOs = [EO]、 Zs = [EO、EO]、 EO mod 2#= 1、 EO mod 2#= 0; EOs = [EO]、 Zs = [EO、EO]、 EO mod 2#= 0、 EO mod 2#= 1; false。
これは、回答と解決策の違いを示しています。ここで2つの答えが得られますが、どちらにも解決策は含まれていません。ほとんどの場合、回答には1つ以上の解決策が含まれていますが、この場合のように何も含まれていない場合もあります。このような回答は、不整合と呼ばれることもあります。
不整合は、必ずしも実装のバグとは見なされません。これらはむしろエンジニアリングのトレードオフです。一貫性を確保することは、実際のメリットと比較して非常にコストがかかる可能性があります。そして:Prologは間違った答えを生成しません:保持しなければならない条件が示されています。その条件が偽であることが判明したとしても。
この回答は、 clpfd、meta-predicate tpartition/4
、およびreifiedtestに基づいていzodd_t/2
ます。
:- use_module(library(clpfd)).
tpartition/4
と組み合わせて使用すると、次のzodd_t/2
ように簡単に記述できます。
?- tpartition(zodd_truth,[1,2,3,4,5,6],Es,Os).
Es = [1,3,5], Os = [2,4,6]. % succeeds deterministically
@Will Nessからの回答は、適切で詳細です。Prologが提供する場合は、「高階」ビルトイン(つまり、述語を引数として受け取る述語)を使用する可能性を追加します。
separate_parity(L, E, O) :-
partition(is_even, L, E, O).
is_even(N) :- N mod 2 =:= 0.
ビルトインの簡単な説明はここにあります。