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去哪里,他们在每次递归调用中都会改变?
答案 0 :(得分:2)
作为“我的变量在哪里”的非常基本解释,请考虑此示例模块中的倒计时功能:
-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
或do while
或[插入表单]。
正如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乐队开始bnot bsl bsr bxor case catch cond div end fun如果不让或者orelse接收rem尝试当xor
答案 1 :(得分:1)
你只需要重新开始:
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})
不同。)
并且每次递归调用都会改变
是的,正如你所看到的那样。