最近看到一道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列表解析表达式中,|| 左边用以生成列表元素,相当于构造器;右边由赋值语句和条件语句构成,也可以只有赋值语句。
% 列表解析
[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