Erlang递归

递归是 Erlang 的重要组成部分。首先,让我们通过实现阶乘程序来了解简单的递归。

  1. -module(helloworld).
  2. -export([fac/1,start/0]).
  3. fac(N) when N == 0 -> 1;
  4. fac(N) when N > 0 -> N*fac(N-1).
  5. start() ->
  6. X = fac(4),
  7. io:fwrite("~w",[X]).

对于上面的例子,有以下几点需要注意:

  • 我们首先定义一个函数 fac(N);

  • 我们可以通过定义递归函数 fac(N) 递归;

上面的代码的输出结果是:

  1. 24

实用方法递归

在本节中,我们将详细了解不同类型的递归及其在 Erlang 中的使用。

长度递归

以递归一个更有效的方法可以用于确定一个列表的长度,现在来看看一个简单的例子。列表中有多个值,如[1,2,3,4]。

让我们用递归的方法来看看如何能够得到一个列表的长度。

示例

  1. -module(helloworld).
  2. -export([len/1,start/0]).
  3. len([]) -> 0;
  4. len([_|T]) -> 1 + len(T).
  5. start() ->
  6. X = [1,2,3,4],
  7. Y = len(X),
  8. io:fwrite("~w",[Y]).

以下是上述程序需要说明的一些关键点

  • 第一个函数 len([]) 用于特殊情况的条件:如果列表为空。

  • [H|T] 模式来匹配一个或多个元素的列表,如长度为1的列表将被定义为 [X|[]],而长度为 2 的列表将被定义为 [X|[Y|[]]] 。

注意,第二元素是列表本身。这意味着我们只需要计数第一个,函数可以调用它本身在第二元素上。在列表给定每个值的长度计数为 1 。

上面的代码的输出结果是:

  1. 4

尾部递归

要了解尾递归是如何工作的,让我们来了解下面的代码在上一节中是如何工作的。

语法

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

回答 1 + len(Rest) 需要 len(Rest) 。函数 len(Rest) 根据需要自行调用另一个函数的结果。该补充将得到堆积,直到最后一个被发现,然后才会计算最终结果。尾递归旨在通过减少它们,以消除这种操作堆叠。

为了达到这个目的,我们将需要保持一个额外的临时变量作为函数的一个参数。上述临时变量有时被称为累加器并用来存储计算的结果,因为它们会限制调用增长。

让我们来看看尾递归的一个例子:

示例

  1. -module(helloworld).
  2. -export([tail_len/1,tail_len/2,start/0]).
  3. tail_len(L) -> tail_len(L,0).
  4. tail_len([], Acc) -> Acc;
  5. tail_len([_|T], Acc) -> tail_len(T,Acc+1).
  6. start() ->
  7. X = [1,2,3,4],
  8. Y = tail_len(X),
  9. io:fwrite("~w",[Y]).

上面的代码的输出结果是:

  1. 4

重复(复本)

让我们来看看递归的例子。这一次我们写一个函数,它接受一个整数作为其第一个参数,然后有一个其他子句作为其第二个参数。它将由整数指定创建多个副本的列表。

让我们来看看这个例子如下:

  1. -module(helloworld).
  2. -export([duplicate/2,start/0]).
  3. duplicate(0,_) ->
  4. [];
  5. duplicate(N,Term) when N > 0 ->
  6. io:fwrite("~w,~n",[Term]),
  7. [Term|duplicate(N-1,Term)].
  8. start() ->
  9. duplicate(5,1).

上面的代码的输出结果是:

  1. 1,
  2. 1,
  3. 1,
  4. 1,
  5. 1,

列表反转

有无止境的在 Erlang 中使用递归。让我们现在快速地来看看如何使用递归来反转列表的元素。

下面的程序可用于实现此目的。

示例

  1. -module(helloworld).
  2. -export([tail_reverse/2,start/0]).
  3. tail_reverse(L) -> tail_reverse(L,[]).
  4. tail_reverse([],Acc) -> Acc;
  5. tail_reverse([H|T],Acc) -> tail_reverse(T, [H|Acc]).
  6. start() ->
  7. X = [1,2,3,4],
  8. Y = tail_reverse(X),
  9. io:fwrite("~w",[Y]).

上面的代码的输出结果是:

  1. [4,3,2,1]

以下是上述程序需要说明的一些关键点:

  • 我们再次使用临时变量 Acc 存储列表中的每个元素

  • 调用递归尾反转,确保最后一个元素被放入新列表的第一位置

  • 递归调用尾反向列表中的每个元素