Erlang-recursion
アーラン-再帰
再帰はErlangの重要な部分です。 まず、階乗プログラムを実装することにより、単純な再帰を実装する方法を見てみましょう。
例
-module(helloworld).
-export([fac/1,start/0]).
fac(N) when N == 0 -> 1;
fac(N) when N > 0 -> N*fac(N-1).
start() ->
X = fac(4),
io:fwrite("~w",[X]).
上記のプログラムについては、次のことに注意する必要があります-
- 最初にfac(N)という関数を定義しています。
- fac(N)を再帰的に呼び出すことにより、再帰関数を定義できます。
上記のプログラムの出力は-
出力
24
再帰への実用的なアプローチ
このセクションでは、Erlangでのさまざまなタイプの再帰とその使用法を詳細に理解します。
長さの再帰
再帰へのより実用的なアプローチは、リストの長さを決定するために使用される簡単な例で見ることができます。 リストには、[1,2,3,4]などの複数の値を含めることができます。 再帰を使用して、リストの長さを取得する方法を見てみましょう。
例
-module(helloworld).
-export([len/1,start/0]).
len([]) -> 0;
len([_|T]) -> 1 + len(T).
start() ->
X = [1,2,3,4],
Y = len(X),
io:fwrite("~w",[Y]).
上記のプログラムについては、次のことに注意する必要があります-
- 最初の関数* len([])*は、リストが空の場合の特別な場合の条件に使用されます。
- 長さ1のリストは [X | []] として定義され、長さ2のリストは* [Xとして定義されるため、1つ以上の要素のリストと一致する [H | T] パターン| [Y | []]] *。 2番目の要素はリスト自体であることに注意してください。 つまり、最初の要素を数えるだけで、関数は2番目の要素で自分自身を呼び出すことができます。 リスト内の各値は、長さ1としてカウントされます。
上記のプログラムの出力は次のようになります-
出力
4
末尾再帰
末尾再帰の仕組みを理解するために、前のセクションの次のコードの仕組みを理解しましょう。
構文
len([]) -> 0;
len([_|T]) -> 1 + len(T).
1 + len(Rest)に対する答えは、len(Rest)の答えを見つける必要があります。 関数len(Rest)自体は、別の関数呼び出しの結果を見つける必要がありました。 足し算は最後の足しが見つかるまで積み上げられ、そのときだけ最終的な結果が計算されます。
テール再帰は、発生する操作を減らすことで、このような操作の積み重ねをなくすことを目的としています。
これを実現するために、追加の一時変数を関数のパラメーターとして保持する必要があります。 前述の一時変数はアキュムレータと呼ばれることもあり、計算の結果を保存する場所として機能し、呼び出しの増加を制限します。
末尾再帰の例を見てみましょう-
例
-module(helloworld).
-export([tail_len/1,tail_len/2,start/0]).
tail_len(L) -> tail_len(L,0).
tail_len([], Acc) -> Acc;
tail_len([_|T], Acc) -> tail_len(T,Acc+1).
start() ->
X = [1,2,3,4],
Y = tail_len(X),
io:fwrite("~w",[Y]).
上記のプログラムの出力は-
出力
4
複製する
再帰の例を見てみましょう。 今回は、最初のパラメーターとして整数を、次に2番目のパラメーターとして他の用語を使用する関数を作成してみましょう。 その後、整数で指定された数だけ用語のコピーのリストを作成します。
この例がどのように見えるか見てみましょう-
-module(helloworld).
-export([duplicate/2,start/0]).
duplicate(0,_) ->
[];
duplicate(N,Term) when N > 0 ->
io:fwrite("~w,~n",[Term]),
[Term|duplicate(N-1,Term)].
start() ->
duplicate(5,1).
上記のプログラムの出力は次のようになります-
出力
1,
1,
1,
1,
1,
リストの反転
Erlangで再帰を使用できる範囲はありません。 再帰を使用してリストの要素を逆にする方法を見てみましょう。 次のプログラムを使用して、これを達成できます。
例
-module(helloworld).
-export([tail_reverse/2,start/0]).
tail_reverse(L) -> tail_reverse(L,[]).
tail_reverse([],Acc) -> Acc;
tail_reverse([H|T],Acc) -> tail_reverse(T, [H|Acc]).
start() ->
X = [1,2,3,4],
Y = tail_reverse(X),
io:fwrite("~w",[Y]).
上記のプログラムの出力は次のようになります-
出力
[4,3,2,1]
上記のプログラムについては、次のことに注意する必要があります-
- ここでも、一時変数の概念を使用して、リストの各要素をAccという変数に格納します。
- 次に tail_reverse を再帰的に呼び出しますが、今回は最後の要素が新しいリストに最初に配置されるようにします。
- 次に、リスト内の各要素に対してtail_reverseを再帰的に呼び出します。