您的位置:首页 > 其它

erlang循环结构:尾递归,列表解析

2014-03-20 23:39 513 查看
最近看到一道erlang面试题,要求分别用尾递归,lists模块,列表解析找出0-9的偶数。

-module(test).
-export([tail_loop/0, lists_func/0, list_comp/0]).

% 尾递归
tail_loop() ->
tail_loop( get_num(), []).

tail_loop([], List) ->
List;
tail_loop([F | Other], List) ->
tail_loop( Other, List ++ (if F rem 2 == 0 -> [F]; true -> [] end) ).

% lists模块
lists_func() ->
lists:foldl(fun(X, List) ->
if X rem 2 == 0 -> List ++ [X];
true -> List
end
end, [], get_num()).

% 列表解析
list_comp() ->
[X ||  X<- get_num(), X rem 2 == 0].

% 生成0到9的数字
get_num() ->
lists:seq(0,9).

我们知道,ErLang不支持变量重复赋值,因而也不支持循环语句。erlang能使用的循环结构只有递归和列表解析。

现在看下erlang递归,erlang这里主要用的是尾递归。

先看下erlang递归和尾递归的区别,如下例子:

% 递归
loop(0) ->
1;
loop(N) ->
N * loop(N-1).

% 尾递归
tail_loop(N)->
tail_loop(N, 1).

tail_loop(0, R)->
R;
tail_loop(N, R) ->
tail_loop(N-1, N *R).

不难看出,erlang尾递归是通过参数来传递实际结果。普通递归用到的栈空间和列表的长度成正比,尾递归不需要再次申请栈空间。如果递归的次数过多,显然尾递归比较合适。至于说哪个递归速度快,erlang说法有争议

It depends. On Solaris/Sparc, the body-recursive function seems to be slightly faster, even for lists with very many elements. On the x86 architecture, tail-recursion was up to about
30 percent faster.

接下来看看erlang列表解析,看个例子:

1> [X || X <- [1,2,a,3,4,b,5,6]].
[1,2,a,3,4,b,5,6]

2> [X || X <- [1,2,a,3,4,b,5,6], X > 3].
[a,4,b,5,6]

3> [X || X <- [1,2,a,3,4,b,5,6], integer(X), X > 3].
[4,5,6]

4> [{X, Y} || X <- [1,2,3], Y <- [a,b]].
[{1,a},{1,b},{2,a},{2,b},{3,a},{3,b}]


在erlang列表解析表达式中,|| 左边用以生成列表元素,相当于构造器;右边由赋值语句和条件语句构成,也可以只有赋值语句。

实际上,erlang列表解析在运行时会转换成一个临时函数

% 列表解析
[Expr(E) || E <- List]

% 解析成的临时函数
'lc^0'([E|Tail], Expr) ->
[Expr(E)|'lc^0'(Tail, Expr)];
'lc^0'([], _Expr) -> [].
总的来说,列表递归函数和尾递归加反转没有太大差别。因此,可以忽略列表函数的性能损失(R12B)。

参考
http://blog.csdn.net/mycwq/article/details/21631123 http://www.erlang.org/doc/efficiency_guide/listHandling.html http://www.erlang.org/doc/programming_examples/list_comprehensions.html http://www.erlang.org/doc/efficiency_guide/myths.html#tail_recursive
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: