erlang迴圈結構:尾遞迴,列表解析
阿新 • • 發佈:2019-01-31
最近看到一道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