【问题标题】:How does the recursive call work in this erlang function?递归调用在这个 erlang 函数中是如何工作的?
【发布时间】:2018-04-03 01:28:31
【问题描述】:
fun({0, M}) -> {M+1, M-2};
fun({N, M}) ->
 {A, B} = fun({N-1, M+1}),
            {B, A+1}.

所以我有点不确定 A 和 B 将是什么以及下一个递归调用将如何。假设 2,2

原来如此

f(2,2) -> {A,B} = fun({1,3}), {B,A+1}
f(1,3) -> {A,B} = fun({0,4}), {B,A+1}
f(0,4) -> {5,2}

但是 A 和 B 去哪里了,它们在每个递归调用中会发生变化吗?

【问题讨论】:

  • 每次调用都是一个新的上下文——例外是当你故意关闭一些外部状态时。考虑备份一些递归习语的更一般的解释:Explanation of lists:foldl function

标签: function recursion erlang


【解决方案1】:

作为对“我的变量在哪里”的非常基本解释,考虑一下这个示例模块中的倒计时功能:

-module(example).
-export([countdown/1]).


-spec countdown(non_neg_integer()) -> ok.

countdown(0) ->
    io:format("Blastoff!~n");
countdown(N) when N > 0 ->
    ok = io:format("Counting down in: ~w~n", [N]),
    Next = N - 1,
    countdown(Next).

如果我们达到基本情况,即0,那么我们就会停止。整个函数的返回值是原子ok(因为这是成功调用io:format/2的返回值)。

如果输入大于0,那么我们匹配第二个子句,这意味着我们为这个特定的迭代指定N 唯一的输入参数。我们要做的下一件事是进行输出调用。然后我们将Next 赋值给N - 1。然后我们使用当前调用主体中Next 的值作为输入参数再次调用相同的函数(循环)。

下一次迭代所有变量都是全新的,因为这是一个全新的执行上下文。旧的N 和Next 不再存在。事实上,它们并不存在于堆栈中的任何地方,因为 Erlang 使用“tail call optimization”来维护constant space 中的递归尾调用,就像大多数其他语言会执行显式的for 或while 或@ 987654340@ 或 [插入表格]。

正如 Alexy 所指出的,请注意标记 fun——它是 Erlang 中的关键字,而不是合法的函数名称。它是anonymous function(也称为lambda)的非名称。换句话说,除非您提供标签,否则每个匿名函数的名称都只是fun。

fun 也是用于按标签引用函数(用作值本身)而不是调用它的关键字。例如,countdown(10) 使用参数10 调用上述函数。 引用函数作为fun countdown/1 将函数本身作为值返回。也就是说,顺便说一下,为什么模块顶部的函数导出声明写成-module([countdown/1]),因为那是这个函数的显式名称。考虑一下:

1> c(example).
{ok,example}
2> example:countdown(2).
Counting down in: 2
Counting down in: 1
Blastoff!
ok
3> Countdown = fun example:countdown/1.
#Fun<example.countdown.1>
4> Countdown(2).
Counting down in: 2
Counting down in: 1
Blastoff!
ok

当我谈到这个主题时......

与大多数语言相比,Erlang 的关键字很少(实际上语法也很少)。这里是the list of reserved words:

andalso band begin bnot bor bsl bsr bxor case catch cond div end fun if let not of or orelse receive rem try when xor

【讨论】:

    【解决方案2】:

    你只需要返回:

    f({1, 3}) -> {A, B} = {5, 2}, {B, A+1} -> {2, 6}
    f({2, 2}) -> {A, B} = {2, 6}, {B, A+1} -> {6, 3}
    

    (注意fun是Erlang中的关键字,f(N,M)与f({N,M})不一样)

    它们是否在每次递归调用中发生变化

    是的,如您所见。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-01
      • 2011-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-14
      • 2019-03-05
      相关资源
      最近更新 更多