Erlang-再帰

再帰は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]などの複数の値を含めることができます。再帰を使用して、リストの長さを取得する方法を見てみましょう。

Example

-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([]) リストが空の場合、特殊なケースの条件に使用されます。

  • ザ・ [H|T] 長さ1のリストは次のように定義されるため、1つ以上の要素のリストと照合するパターン [X|[]] 長さ2のリストは次のように定義されます。 [X|[Y|[]]]。2番目の要素はリスト自体であることに注意してください。つまり、最初の要素を数えるだけで、関数は2番目の要素で自分自身を呼び出すことができます。リスト内の各値を指定すると、長さは1としてカウントされます。

上記のプログラムの出力は次のようになります-

Output

4

末尾再帰

末尾再帰がどのように機能するかを理解するために、前のセクションの次のコードがどのように機能するかを理解しましょう。

Syntax

len([]) -> 0; 
len([_|T]) -> 1 + len(T).

1 + len(Rest)の答えを見つけるには、len(Rest)の答えが必要です。次に、関数len(Rest)自体が、別の関数呼び出しの結果を見つける必要がありました。追加は、最後の追加が見つかるまでスタックされ、その後、最終結果が計算されます。

末尾再帰は、発生時に操作を減らすことで、この操作の積み重ねを排除することを目的としています。

これを実現するには、関数のパラメーターとして追加の一時変数を保持する必要があります。前述の一時変数はアキュムレータと呼ばれることもあり、呼び出しの増加を制限するために、計算結果を保存する場所として機能します。

末尾再帰の例を見てみましょう-

Example

-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]).

上記のプログラムの出力は次のとおりです。

Output

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を再帰的に呼び出します。