3

バックグラウンド

述語eval(P、A、R)を書く必要があります。ここで、
Pは多項式係数のリストを表します。つまり、1 + 2x + 3x^2は[1,2,3]として表されます。
AはXの値を表します
。RはX=Aでの多項式の結果です。

例: eval([3,1,2]、3、R)はR = 24を生成し ます。*編集、以前は正しくない例

この記事のアキュムレータとLearnPrologNowの例を使用しようとしています

私のアルゴリズム:
0。結果変数と指数変数を0に初期化し
ます。1。リストの先頭を取ります。
2.リストの先頭にA^(指数)を掛けます。
3.結果と指数を更新します。

私のコード:

eval(P,A,R) :- accEval(P,A,0,0,R).      
accEval(([H|T]),A,Pow,Accres,R) :- 
        Rnew is (Accres+H*(A**Pow)), 
        Pownew is Pow+1, 
        R = Accres, 
        accEval(T,A,Pownew,Rnew,Rnew).  % *See below
accEval([],A,Pow,Accres,Accres).

% *Previously, when the second Rnew in this line was R instead, output was "no".

トレースを生成します:

| ?- eval([1,2],3,R).
  1    1  Call: eval([1,2],3,_20) ? 
  2    2  Call: accEval([1,2],3,0,0,_20) ? 
  3    3  Call: _126 is 0+1*3**0 ? 
  3    3  Exit: 1.0 is 0+1*3**0 ? 
  4    3  Call: _157 is 0+1 ? 
  4    3  Exit: 1 is 0+1 ? 
  5    3  Call: accEval([2],3,1,1.0,1.0) ? 
  6    4  Call: _218 is 1.0+2*3**1 ? 
  6    4  Exit: 7.0 is 1.0+2*3**1 ? 
  7    4  Call: _249 is 1+1 ? 
  7    4  Exit: 2 is 1+1 ? 
  8    4  Call: accEval([],3,2,7.0,7.0) ? 
  8    4  Exit: accEval([],3,2,7.0,7.0) ?  % We have the correct answer.
  5    3  Exit: accEval([2],3,1,1.0,1.0) ? % Wait! What are you doing!?
  2    2  Exit: accEval([1,2],3,0,0,0) ?   % Why is this falling back out?
  1    1  Exit: eval([1,2],3,0) ? 

R = 0  % Incorrect. The answer should be 7.

私のコードで述べたように、以前の試みではRの値は生成されず、代わりに「no」または他の実装では「yes」が生成されました。

質問

結果が失われ、元の呼び出しに戻されないのはなぜですか?

4

3 に答える 3

2

それは少し簡単です:

eval(P,A,R) :- accEval(P,A,0,0,R).
accEval(([H|T]),A,Pow,Accres,R) :-
        Rnew is (Accres+H*(A**Pow)),
        Pownew is Pow+1,
        accEval(T,A,Pownew,Rnew,R).  % *See below
accEval([],_A,_Pow,Accres,Accres).

しかし、あなたの例は正しくないようです

?-  eval([3,2,1],3,R).
R = 18.

実際、X=3の3+2 * X + X ^ 2は、18を生成します。

于 2013-03-06T22:20:15.207 に答える
2

再帰の最後にアキュムレータ値と統合されるはずの変数は、すでに値にバインドされています。アキュムレータの使用方法は次のとおりです。

  • 述語を最初に「呼び出す」ときに、アキュムレータに初期値を指定します
  • アキュムレータを使用して、累積値を再帰呼び出しに渡します
  • 再帰終了句のアキュムレータと結果を統合します

経験則として、述語の先頭にあるResult変数は、再帰呼び出しに渡される変数と同じです。このように、(再帰の終わりの句で)最後に実際の結果と統合されると、再帰から呼び出し元に渡されます。

于 2013-03-06T22:21:54.840 に答える
0

ここでの戦略は、いわゆるホーナースキーマである可能性があります。ホーナースキーマでは、べき関数(**)/ 2または(^)/2は必要ありません。ホーナースキーマは次のように述べています。

a_0 + a_1*x + .. + a_n-1*x^n-1 + a_n*x^n =

a_0 + x*(a_1 + .. + x*(a_n-1 + x*a_n)..)

逆の順序で係数を提供することを許可した場合[a_n、..、a_0]ホーナースキーマは次のようにPrologに簡単に実装されます。

eval([C|L], X, R) :-
    eval(L, C, X, R).

eval([C|L], A, X, R) :-
    B is A*X+C,
    eval(L, B, X, R).
eval([], A, _, A).

ボーナスとして、ホーナースキームは数値的に安定しています。実行例を次に示します。

?- eval([2,1,3],3,R).
R = 24
于 2016-11-09T19:54:57.743 に答える