5

私が書いているプログラムの場合、リストのリストを作成する必要があります。リストのリストには、製品を表す数字のペアと、指定された2つの数字の合計が含まれます。

今のところ、リストにリストを追加する回数を指定できる関数があります。これは、後ですべての機能で拡張されます。

これが私が持っているものです:

s1(0, X).
s1(Q, X) :-
    N is Q - 1,
    multiply(2, 3, Y),
    A = Y ,
    add(2, 3, Z),
    B = Z,
    addToEnd([A], [B], X),
    s1(N,X).

multiply(A, B, C):-
    C is A * B.

add(A, B, C) :-
    C is A + B.

addToEnd([], L, L).
addToEnd([H|T], L2, [H|L3]) :-
    addToEnd(T, L2, L3).

ただし、s1(2,X)たとえば実行すると、[6,5]返され、それ以外は何も起こらず、ハングします。私が走るときs1(0,X)、私は得るtrue、そしてfalse私が打つとき;

誰かがこれを手伝ってくれますか?何が間違っているのかわからないので、うまくいくと思います!

これがどのように機能するかを明確にするために:私は、を呼び出しs1(2,X). N = 1[6,5]リストにX([[6,5]]) s1(1,X). N=0追加[6,5]し、リストに追加しましたX ([[6,5],[6,5]]) s1(0,X). X = [[6,5],[6,5]]

4

1 に答える 1

6

ですから、ここで言うことはたくさんあります。何よりもまず、ほとんどの宣言型言語と同様に、変数は実際には値を変更できません。

それが意味することは、それはあなたが期待X = 1.するように統一1されるということです、しかしあなたがあなたのクエリ()でその後に追加するならば、Prologは言うでしょう。その背後にある理由は、あなたが統一することができず、それが本当にになっているため、に統一することができないということです。XX = 2.X = 1, X = 2.false12X1X2

ただし、HaskellやOcamlなどとは異なりますが、のように部分的に変数をバインドできますX = h(Y).X = h(a(Z)).そうすれば、前述の言語ではできなかったものの、それをさらに統合できるようになります(変数は実際には値の単なるエイリアスです)。

なぜ彼はあなたが不思議に思うことをすべて私に言うのですか?さて、それがここでのあなたの主な問題です。最初ににバインドX[6, 5]、次にそれを他のものにさらにバインドすることを期待します。変数がグラウンドされると(つまり、その中に自由変数が含まれないと)、その値を再び変更することはできません。

したがって、ここでは、再帰は何もしませんが、最終的にはX誤りであることがわかります。addToEnd/3ただし、ここでは、毎回同じ引数(、、および)を使用し[6][5]呼び出すことになりますので、そうではありません[6, 5]

そうは言っても、コードを改善する方法を見てみましょう。

まず、コメント:

multiply(2, 3, Y),
A = Y ,
add(2, 3, Z),
B = Z,
addToEnd([A], [B], X),

書くことができます

multiply(2, 3, Y),
add(2, 3, Z),
addToEnd([Y], [Z], X),

A何度も使用しないので、情報を失うことなくB

さて、ちょっと忘れてaddToEnd/3、何が欲しいか考えてみましょう。

あなたが入った場合s1(0, Q)、あなたは本当にQ自由に滞在したいですか?それがあなたが現時点で述べていることだからです。その場合、バインドする方が理にかなってQいます。[]さらに、すぐにわかるように、これは再帰的なベースケースになります。

s1(0, []).

言うためのショートカットです

s1(0, Q) :- Q = [].

Prologは節の先頭(前の部分:-)で統一を行うためです。

次に、少しごまかしますが、それはただ明確に保つことです。s1(4, Q)から行くとき、s1(5, Q)Qが微積分のもう1つの値を保持することを期待すると言うことができます。

ここでは、次のように述べることができます。

s1(N, [SomeCalculus|Q]) :-
    PreviousN is N - 1,
    s1(PreviousN, Q).

今、私たちはただに値を与える必要がありますSomeCalculus

s1(N, [SomeCalculus|Q]) :-
    PreviousN is N - 1,
    X is 2 * 3,
    Y is 2 + 3,
    SomeCalculus = [X, Y],
    s1(PreviousN, Q).

または、正しく従えば、次のように直接書くことができます。

s1(N, [[X, Y]|Q]) :-
    PreviousN is N - 1,
    X is 2 * 3,
    Y is 2 + 3,
    s1(PreviousN, Q).

したがって、完全なプログラムは次のようになります。

s1(0, []).
s1(N, [[X, Y]|Q]) :-
    PreviousN is N - 1,
    X is 2 * 3,
    Y is 2 + 3,
    s1(PreviousN, Q).

;さて、それをテストすると、キーを押したときにプログラムがあなたと同じようにループすることに気付くかもしれません。これは、Prologが2番目の条項も適用できると考えているため0 です。

それでは、プログラムをもう一度編集しましょう。

s1(0, []).
s1(N, [[X, Y]|Q]) :-
    N > 0,
    PreviousN is N - 1,
    X is 2 * 3,
    Y is 2 + 3,
    s1(PreviousN, Q).

今、すべてが順調です。

これが、再帰を通じて適切な述語を構築する方法をよりよく理解するのに役立つことを願っています。addToEnd/3変数についての私のとりとめのない話は、それの何が悪いのかについてすでに多くのことを教えてくれたはずなので、私はあなたの述語を修正するのに多くの時間を費やしませんでした。

于 2012-04-07T23:55:33.843 に答える