0


0

プロローグ-基本ケースからの戻り値

わかりました、これは取り引きです:

  • 私はシャツの山を2つ持っています

  • 私は各パイルからランダムなシャツを取り、新しいものに入れたい pile

  • 次に、新しいパイルを取り出します

そして、これがそのコードです。

mix([],[],_).
mix(P1,P2, Pile):-
    takeshirt(P1,1,Taken1,Rem1), takeshirt(P2,1,Taken2,Rem2), #Take one
    append(Pile,Taken1,New),     append(New,Taken2,NewPile),  #Put both of them
    mix(Remain1,Remain2,NewPile).

結果は次のようになります。

1 ?- mix([a,b],[c,d],NewPile).
NewPile = [] .

私はそれが以下のようになりたいです

1 ?- mix([a,b],[c,d],NewPile).
NewPile = [b, d, a, c] .

または結果が何であれ。 グラフィカルデバッガーで確認したところ、* mix *への最後の呼び出しが発生すると、バインディングが次のようになることがわかりました。

P1 = Taken1 = [b]
P2 = Taken2 = [c]
Pile           = [a, d]
Rem1 = Rem2 = []
New         = [a, d, b]
NewPile     = [a, d, b, c] #<--- Interresting

したがって、次の呼び出しが最後に行われるとき、必要な値はNewPileにあります。

mix([],[],_).

起こる。 この後、それはカードの家のように崩壊します。

だから質問は:

mix([],[],_).

基本ケースから_値を返したいのですが、このルール* mix *は実際には2つのパイルを送信して新しいパイルを取り出す上位インスタンスから使用されます。

更新: + *テイクシャツ*ルールに関するいくつかのコメントを明確にするため、ここにあります:

takeshirt(_,0,[],_).
takeshirt(List,Number,[Element|Taken],Remain) :- N > 0,
    length(List,Len),
    Index is random(Len) + 1,
    removeshirt_at(Element,List,Index,Remain),
    Number1 is Number - 1,
    takeshirt(Remain,Number1,Taken,Remain).

1 回答


2


コードに対する次の変更を検討してください。

mix([], [], []) :- !.
mix(P1, P2, Pile) :-
    takeshirt(P1, 1, Taken1, Rem1),
    takeshirt(P2, 1, Taken2, Rem2),
    append(Taken1, Taken2, Pile0),
    mix(Rem1, Rem2, Pile1),
    append(Pile0, Pile1, Pile).

「リストアトム」として「シャツ」を蓄積する必要があるようです。 ここでは、両方の入力リストが空のリストである場合に基本ケース(最初の節)がヒットするまで、 mix / 3(` Pile`)の3番目の引数に再帰的に追加します(カット `!`は2番目の句のバインディングパターンが最初の句と一致するため、ここで必要なので、除外します)。 すべてのステップで各入力リストからシャツを取得する2番目の句の動作では、最初から同じ長さである必要があります。

これをテストするために、 `takeshirt / 4`の次の定義を使用しました。

takeshirt(Ps, _, [P], Rem) :-
    select(P, Ps, Rem).

リストから1つの要素(シャツ)を取り出して残りを返すために `select / 3`が使用されているため、ここの2番目の引数は使用されていないことに注意してください。 「select」の後にカット(「!」)がないため、この述部はリストから他のすべての要素(シャツ)を選択する際にバックトラックできます。 この定義でサンプルクエリを実行すると、次のようになります。

1 ?- mix([a,b],[c,d],NewPile).
NewPile = [a, c, b, d] ;
NewPile = [a, d, b, c] ;
NewPile = [b, c, a, d] ;
NewPile = [b, d, a, c] ;
false.

…​we can see that mix/3 enumerates all possible 'piles' on 最初のパイル(最初の入力リスト)からシャツを取得し、2番目のパイル(2番目の入力リスト)からシャツを取得するなど、両方の入力リストが空になるまでバックトラックします。 `takeshirt / 4`の定義が選択ポイントを残さない場合(バックトラッキングではない場合)、1つのソリューションしか得られません。