最近看到一道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
endend, , 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 <- [1,2,3], y <- [a,b]].
[,,,,,]
在erlang列表解析表示式中,|| 左邊用以生成列表元素,相當於構造器;右邊由賦值語句和條件語句構成,也可以只有賦值語句。
實際上,erlang列表解析在執行時會轉換成乙個臨時函式
% 列表解析
[expr(e) || e <- list]
% 解析成的臨時函式
'lc^0'([e|tail], expr) ->
[expr(e)|'lc^0'(tail, expr)];
'lc^0'(, _expr) -> .
總的來說,列表遞迴函式和尾遞迴加反轉沒有太大差別。因此,可以忽略列表函式的效能損失(r12b)。
參考
erlang雜記十二 再說尾遞迴
翻了一下list模組,看的時候,突然發現,尾遞迴其實是很容易展開成迴圈的。想起讀書時剛開始學程式,c語言,一直再糾結的乙個問題,就是如何讓乙個函式返回兩個引數的結果,哈哈,不要笑我。do sth sa,sb do sth ha ta la,hb tb lb,sa,sb do sth ta,tb,ha...
用尾遞迴優化Erlang的lists map
用尾遞迴優化erlang的lists map erlang的lists庫中的map函式是這樣寫的 spec map 2 fun d r d r map f,h t f h map f,t map f,when is function f,1 顯然這裡有個問題,f h map f,t 這句沒有用為遞迴...
一般遞迴 尾遞迴 迴圈遞迴
階乘的一般遞迴 int factorial int n 階乘的尾遞迴 int factorial tail int n,int res 階乘的迭代形式 int factorial loop int n 斐波那契數列的一般遞迴 int fibonacci int n 斐波那契數列的尾遞迴 int fi...