2

これについて別の質問を投稿して申し訳ありませんが、ここで輪になっているようです!

私のプログラムでは、リストのリストを作成する必要があります。各サブリストには、X と Y の 2 つの数値と、これら 2 つの数値の合計と積が含まれています。これまでのところ、次のものがあります。

genList(100,N, X,[]).

genList(S,N, X,[[X,Y,Sum,Product]|Xs]):-

    Y is N+1,
    Sum is X+Y,
    NewS is Sum,
    Sum<101,
    Product is X*Y,
    N1 is N+1,
    genList(NewS,N1, X,Xs).

genList(S,N,X,Q):-
    N+X < 101,
    NextX is X + 1,
    genList(0,NextX,NextX,Q).

目標は、sum<= 100 となる数値のすべてのペアを見つけることです。したがって、1 つの開始値について上記を実行すると、X はすべてのペア 1 < X < Y (sum<=100) を検出し、すべての数値 2 を実行します。 -N は、可能なペアの完全なリストを提供します。

興味のある方のために、私が取り組んでいる問題は、ここで説明されている和/積の問題です(ページの 2 番目)。

誰かがこれを手伝ってくれるなら、それは大歓迎です!

また、組み込みのプロローグ述語を使用できないため、findall を使用するよりも複雑な方法でこれを行う必要があります。

この述語によって生成される出力の一部を抜粋すると、次のようになります。

[[5,6,11,30]、[5,7,12,35]、[5,8,13,40]、[5,9,14,45]、[5,10,15,50] ,[5,11,16,55],[5,12,17,60],[5,13,​​18,65],[5,14,19,70],[5,15,20,75] ,[5,16,21,80],[5,17,22,85],[5,18,23,90],[5,19,24,95],[5,20,25,100],[ 5,21,26,105]、[5,22,27,110]、...

かなり近いと思いますが、まだ何かが正しくありません。

数値のペアを循環しますが、「;」を使用する必要があります。すべての回答を表示するには、これは私が望んでいるものではありません。さらに、すべての回答が尽きると false を返します。私はそれを理解することはできません。

また、開始値の完全な回答が得られますが、最後のペアのセットだけが残るまで、毎回サブリストが削除されます。

例: genList(0,48,48,Q)。私に与えます:

[[48,49,97,2352],[48,50,98,2400],[48,51,99,2448],[48,52,100,2496]]
[[48,49,97,2352],[48,50,98,2400],[48,51,99,2448],[48,52,100,2496],[49,50,99,2450],[49,51,100,2499]]
[[48,49,97,2352],[48,50,98,2400],[48,51,99,2448],[49,50,99,2450],[49,51,100,2499]]
[[48,49,97,2352],[48,50,98,2400],[49,50,99,2450],[49,51,100,2499]]
[[48,49,97,2352],[49,50,99,2450],[49,51,100,2499]]
[[49,50,99,2450],[49,51,100,2499]]
false.

ご覧のとおり、毎回サブリストが削除されますが、その理由がわかりません!

4

1 に答える 1

5

さて、あなたはほとんどそこにいます。すでにこの問題にかなりの時間を費やしたので、有効なコードをいくつか示してコメントします。

最初に、引数としてXandを運ぶワーカー述語を呼び出し、それらを次のように初期化します。Y0

validPair(Result) :-
    validPair(0, 0, Result).

次に、基本ケースを処理します。から始めたので0、基本ケースが上限です。逆の方向に進むこともできました。それは単なる選択です。ここでのカットは、次の節Yよりも優れていることを心配する必要がないことを意味することに注意してください。100

validPair(_X, 101, []) :- !.

Xこれは、合計が 未満になる正しい制限に適合する場合100です。最初にすべてが問題ないことを確認してから、!/0述語を使用して実行が最後の句に到達するのをもう一度防ぎます。これは意味がないためです。それが終わったら、興味深い値を計算してリストに追加するだけです。

validPair(X, Y, [[X, Y, Sum, Product]|R]) :-
    Limit is min(100 - Y, Y),
    X =< Limit,
    !,
    Sum is X + Y,
    Product is X * Y,
    NextX is X + 1,
    validPair(NextX, Y, R).

処理する必要がある唯一のケースはX、合計が 未満になるように修正した制限を超えた場合100です。それが起こったら、次からやり直し、 にYリセットX0ます。

validPair(_X, Y, R) :-
    NextY is Y + 1,
    validPair(0, NextY, R).

何か問題がある場合は、コメントで説明を求めてください。

注: ここで使用されているカットは赤いカットです。つまり、述語の正しさは節の順序に完全に依存します。それは悪い習慣です。適切なガードでそれらを補完してみてください(X =< 100たとえば)、それは良い追加になるでしょう:)

編集:

コードを監査してみましょう :D スタイルについてコメントすることから始めましょう: この節 (本体がないためファクトと呼ばれます) では、and を 1 回だけ使用NXます。つまり、それらの値を保存する必要はありません。この場合、名前の前に a を付ける_か、単に匿名変数を使用します_

genList(100,N, X,[]).

になる

genList(100, _N, _X, []).

また

genList(100, _, _, []).

ここでも同じですS。この句では使用されません。初回のみ使用です。_または_Sum、ここでも他の節での使用を文書化したい場合は、それを置き換えることができます (良い習慣です)。次に、2 つの変数を使用してまったく同じ値を保持します。ここには興味がありません。そのためだけに新しい変数を宣言するのではなく、最初の引数としてnextgenList/4を呼び出すだけです。と もSum同じです。この句の適切なバージョンは次のようになります。YN1

genList(S,N, X,[[X,Y,Sum,Product]|Xs]):-
    Y is N+1,
    Sum is X+Y,
    NewS is Sum,
    Sum<101,
    Product is X*Y,
    N1 is N+1,
    genList(NewS,N1, X,Xs).

の中へ

genList(_PreviousSum, N, X,[[X, Y, Sum, Product]|Xs]):-
    Y is N+1,
    Sum is X + Y,
    Sum<101,
    Product is X * Y,
    genList(Sum, Y, X, Xs).

あなたの最後の節には算術の問題があります: N + Xis just the term +(N, X). 値ではありませんN + Xis/2他の句と同じように述語を使用する必要があります。の 2 番目の句と同じ問題ですS。これらの小さな編集は次のようになります。

genList(S,N,X,Q):-
    N+X < 101,
    NextX is X + 1,
    genList(0,NextX,NextX,Q).

の中へ

genList(_PreviousSum, N, X, Q) :-
    Sum is N + X,
    Sum < 101,
    NextX is X + 1,
    genList(0, NextX, NextX, Q).

したがって、現時点では、修正されたプログラムは次のようになります。

genList(100, _N, _X, []).
genList(_PreviousSum, N, X,[[X, Y, Sum, Product]|Xs]):-
    Y is N+1,
    Sum is X + Y,
    Sum<101,
    Product is X * Y,
    genList(Sum, Y, X, Xs).
genList(_PreviousSum, N, X, Q) :-
    Sum is N + X,
    Sum < 101,
    NextX is X + 1,
    genList(0, NextX, NextX, Q).

スタイルの編集だけだったので、動作は変わりません。

それでは、スタイルではなくロジックのどこが間違っていたのかを見てみましょう。まずはベースケース。ここではすべて問題ありません。合計が上限であるかどうか、およびそれが return であるかどうかを確認します[]。完全!

genList(100, _N, _X, []).

さて、あなたの「内部再帰」。ほぼ大丈夫です。私を悩ませている詳細を見てみましょう: 以前の合計を保持する値がありますが、新しい値を計算し、上限 + 1 に対して再テストします。より良いアイデアは、テストPreviousSumに対してテストし、テスト< 100を削除することSum < 101です。そのためだけに議論があるという事実を正当化する方がよいでしょう! さらに、その制限の場合に句の実行を防ぐためにガードが使用されていることはより理解できます。そう、

genList(_PreviousSum, N, X,[[X, Y, Sum, Product]|Xs]):-
    Y is N+1,
    Sum is X + Y,
    Sum<101,
    Product is X * Y,
    genList(Sum, Y, X, Xs).

に変わるだろう

genList(PreviousSum, N, X,[[X, Y, Sum, Product]|Xs]):-
    PreviousSum < 100,
    Y is N+1,
    Sum is X + Y,
    Product is X * Y,
    genList(Sum, Y, X, Xs).

この変更はちょっと文体的なものであり、プログラムの動作を変更するものではないことに注意してください。それでも読みやすくなります!

さて、大きな悪いオオカミ: genList(_PreviousSum, N, X, Q) :- Sum は N + X、Sum < 101、NextX は X + 1、genList(0, NextX, NextX, Q) です。ここで言いたいことはたくさんあります。Sum最初に繰り返しますが、PreviousSumすでに値を保持しているため、計算する必要はありません。< 100次に、代わりにテストする必要があり< 101ます。次に、それをテストする必要がありX >= Nます。これは、2 番目の句ではなく、代わりにこの句を通過したい場合に限られるためです。最後になりましたが、新しい反復を開始する代わりに、genList(0, NextX, NextX, Q)genList(NextX, 0, NextX, Q) で開始する必要があります。ここでは、値を適切にリセットしていません。結果の句は次のとおりです。

genList(PreviousSum, N, X, Q) :-
    PreviousSum < 100,
    N >= X,
    NextX is X + 1,
    genList(NextX, 0, NextX, Q).

ご覧のとおり、2 番目の節 if を通過できないことは定式化されていますN >= X。それが正しいことを保証するために、適切なテストを追加する必要があります。

genList(PreviousSum, N, X,[[X, Y, Sum, Product]|Xs]):-
    PreviousSum < 100,
    N < X,
    Y is N+1,
    Sum is X + Y,
    Product is X * Y,
    genList(Sum, Y, X, Xs).

これで完了です。プログラムは正しいです。

最終版は次のとおりです。

genList(100, _N, _X, []).
genList(PreviousSum, N, X,[[X, Y, Sum, Product]|Xs]):-
    PreviousSum < 100,
    N < X,
    Y is N+1,
    Sum is X + Y,
    Product is X * Y,
    genList(Sum, Y, X, Xs).
genList(PreviousSum, N, X, Q) :-
    PreviousSum < 100,
    N >= X,
    NextX is X + 1,
    genList(NextX, 0, NextX, Q).

変数の命名はまだ不十分です。より明確なバージョンは次のようになります。

genList(100, _X, _Y, []).
genList(PreviousSum, X, Y,[[X, Y, Sum, Product]|Xs]):-
    PreviousSum < 100,
    X < Y,
    NewX is X + 1,
    Sum is X + Y,
    Product is X * Y,
    genList(Sum, NewX, Y, Xs).
genList(PreviousSum, X, Y, Q) :-
    PreviousSum < 100,
    X >= Y,
    NextY is Y + 1,
    genList(NextY, 0, NextY, Q).

ここでまだ問題があります (ええ、終わりはありません :D): 積の合計などを計算する前に変数をインクリメントするという事実は、いくつかの値をスキップすることを意味します。後にインクリメントしてみてください。それは練習としてしましょう:)

于 2012-04-10T18:40:39.513 に答える