递归调用在这个erlang函数中如何工作? [英] How does the recursive call work in this erlang function?

查看:148
本文介绍了递归调用在这个erlang函数中如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  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在哪里去,它们在每个递归调用中都改变了吗?

解决方案

基本解释了我的变量在哪里这个示例模块:

  -module(示例)。 
-export([countdown / 1])。


-spec countdown(non_neg_integer()) - >好。

倒计时(0) - >
io:格式(Blastoff!〜n);
倒数(N)当N> 0 - >
ok = io:format(Counting in:〜w〜n,[N]),
Next = N - 1,
countdown(Next)。

如果我们点击基本情况,它是 0 ,然后我们停下来。整体函数的返回值是原子 ok (因为这是成功调用 io:format / 2 )。



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



下一次迭代所有变量都是全新的,因为这是一个新的执行上下文。旧的 N 下一步不再存在。事实上,他们不会在任何地方存在任何事件,因为Erlang使用尾部调用优化恒定空间中维护递归尾调用,这与大多数其他语言执行操作的方式相同显式,而或[插入表单]。



正如Alexy指出的那样,要小心< fun - 它是Erlang中的一个关键字,不是法定的功能名称。它是匿名函数的非名称(也称为lambda )。换句话说,除非你提供一个标签,否则每个匿名函数的名字就是 fun



fun 也是用于通过标签引用函数的关键字(用作本身的值)而不是调用它。例如, countdown(10)使用参数 10 调用上面的函数。 引用函数为 fun countdown / 1 将函数本身作为一个值返回。也就是说,为什么模块顶部的函数导出声明被写为 -module([countdown / 1]),因为这是这个名字的明确名称功能。考虑到这一点:

  1> C(示例)。 
{ok,example}
2>例如:倒计时(2)。
倒计数:2
倒计数:1
Blastoff!
ok
3>倒计时=有趣的例子:倒计时/ 1。
#Fun< example.countdown.1>
4>倒数(2)。
倒计数:2
倒计数:1
Blastoff!
ok

当我介绍这个主题时...



与大多数语言相比,Erlang的关键字非常少(实际上语法很少)。这是保留字列表


之后和andalso乐队开始bnot bor bsl bsr bxor case抓住cond div乐趣如果let not或orelse接收rem试试xor



fun({0, M}) -> {M+1, M-2};
fun({N, M}) ->
 {A, B} = fun({N-1, M+1}),
            {B, A+1}.

so I am kinda unsure of what the A and B would be and how the next recursive call would be. let say 2,2

so it would be

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}

but where does A and B go and do they change in each recursive call?

解决方案

As a very basic explanation of "where is my variable", consider the countdown function in this example module:

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

If we hit the base case, which is 0, then we stop. The return value of the function overall is the atom ok (because that is the return value of a successful call to io:format/2).

If the input is greater than 0 then we match on the second clause, which means we assign N the sole input argument for this particular iteration. The next thing we do is make our output call. Then we assign Next to the value N - 1. Then we call the same function again (do a loop) using the value of Next in body of the the current call as the input argument.

The next iteration all the variables are totally new because this is a fresh execution context. The old N and Next no longer exist. In fact, they don't event exist on a stack anywhere because Erlang uses "tail call optimization" to maintain recursive tail calls in constant space, the same way most other languages would do an explicit for or while or do while or [insert form].

As Alexy points out, be careful about the token fun -- it is a keyword in Erlang, not a legal function name. It is the non-name of an anonymous function (also known as a lambda). In other words, unless you provide a label, the name of every anonymous function is just fun.

fun is also the keyword that is used to reference a function by label (to use as a value itself) instead of calling it. For example, countdown(10) calls the function above with an argument of 10. Referencing the function as fun countdown/1 returns the function itself as a value. That is, incidentally, why the function export declaration at the top of the module is written as -module([countdown/1]), because that is the explicit name of this function. Consider this:

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

While I'm on the subject...

Erlang has very few keywords compared to most languages (and very little syntax, actually). Here is the list of reserved words:

after and 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

这篇关于递归调用在这个erlang函数中如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆