最近看到一道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