【问题标题】: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 的值作为输入参数再次调用相同的函数(循环)。

下一次迭代所有变量都是全新的,因为这是一个全新的执行上下文。旧的NNext 不再存在。事实上,它们并不存在于堆栈中的任何地方,因为 Erlang 使用“tail call optimization”来维护constant space 中的递归尾调用,就像大多数其他语言会执行显式的forwhile 或@ 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
      相关资源
      最近更新 更多