1

erlang の学習を始めたばかりで、Tail 再帰がゆっくりと私を殺していきます。私はそれを理解することができません。リスト内の他のすべての数値を 2 倍にするプログラムを作成しようとしていますが、末尾再帰を使用してこれを実行しようとしています。

これまでの私のコードは次のとおりです

    stripAndDoubleOdds([H|T]) -> stripAndDoubleOdds([H|T],1,[H|T]).

    stripAndDoubleOdds(F, _, []) -> F;

    stripAndDoubleOdds(_,Index,[H1|T1]) ->

    F = [] ++ 2*lists:nth(Index, [H1|T1]),  

stripAndDoubleOdds(F, Index +2, T1).

数値のリストを与えるとまったく出力が得られませんが、単一の数値を与えると問題なく2倍になります。

インデックスは現在の要素の位置を保持するためのものであり、2 ずつインクリメントされるため、1 つおきの整数を取得して 2 倍にします。私の現在の解決策には、頭を抽出して2倍にし、リストに追加してから、空のリストを取得するまで何度もテールをプロセスに渡す必要があり、この時点でリストFを取得することになっています。たとえば、[1,2,3,4,5] と入力すると、[2,6,,10] のリストが表示されます。

4

2 に答える 2

1

したがって、最初の本体は再帰的です (それほど遅くはありません):

stripAndDoubleOdds([H, _|T]) -> [2*H | stripAndDoubleOdds(T)];
stripAndDoubleOdds([H]) -> [2*H];
stripAndDoubleOdds([]) -> [].

テール再帰になりました

stripAndDoubleOdds(L) -> lists:reverse(stripAndDoubleOdds(T, [])).

stripAndDoubleOdds([H, _|T], Acc) -> stripAndDoubleOdds(T, [2*H|Acc]);
stripAndDoubleOdds([H], Acc) -> [2*H|Acc];
stripAndDoubleOdds([], Acc) -> Acc.

非常に効率的でもなく、良くもないリスト内包表記バージョンを作成することもできます

stripAndDoubleOdds(L) ->
    [ 2*X || {X, I} <- lists:zip(L, lists:seq(1,length(L))), I rem 2 =:= 1 ].
于 2013-12-01T21:12:03.783 に答える
1

リストで動作する末尾再帰関数を作成するには、パターンは常に同じです。最初のリストに加えて、アキュムレータ パラメーターを持つ関数を呼び出します。実行する関数に応じて、accumulator は整数、空のリスト、またはアルゴリズムに必要な初期値になります。

あなたの例では、最初のリストからリストを作成したいとします。アキュムレータは、後続の呼び出し中に入力する空のリストになります。

再帰アルゴリズムについては、再帰を停止して結果を返すことを許可する終了ケースを定義する必要があります。あなたの場合、それは初期リストが空になったときです。

読みやすいこのソリューションを提案します(IMO)

strd(L) -> strd(L,1,[]). % as you did, I use an integer to detect the odd indices

strd([],_,Acc) -> lists:reverse(Acc); 
%    if the order is important, you should reverse the resulr at the end rather than keeping the right order during
%    the evaluation using the ++ operator. The ++ operator force a copy of the whole list while the construction with
%    [A|B] does not need to copy B.
strd([_|Q],0,Acc) -> strd(Q,1,Acc);
strd([H|Q],1,Acc) -> strd(Q,0,[2*H|Acc]). 
%    I simply toggle the integer betwwen 1 and 0 to select the right operation using pattern matching

Hynek の例は、2 番目のエンド ケースを追加する任意の長さの af リストで機能します。

stripAndDoubleOdds(L) -> stripAndDoubleOdds(L, []).

stripAndDoubleOdds([H, _|T], Acc) -> stripAndDoubleOdds(T, [2*H|Acc]);
stripAndDoubleOdds([H], Acc) -> lists:reverse([2*H|Acc]);
stripAndDoubleOdds(_, Acc) -> lists:reverse(Acc).
于 2013-12-01T22:37:34.340 に答える