用尾遞迴優化Erlang的lists map

2021-08-22 14:23:27 字數 764 閱讀 8843

用尾遞迴優化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)]"這句沒有用為遞迴實現,在list很大的情況下,可能會耗費很大的棧空間,並且在效率上也有很大的損失.下面是通過尾遞迴實現的list map/2 函式:

-module(map_tail).

-export([map/2]).

map(_, , r) -> lists:reverse(r);% 最後一次呼叫,需要把列表反轉一下,否則,取得元素順序會掉轉

map(f, [h|t], r) -> map( f, t, [f(h)|r] ). %

這裡是尾遞迴的關鍵,本來函式生成新狀態是放在棧上儲存的( [f(h)|map(f, t)];),在尾遞迴的寫法中,狀態被轉移到第三個引數中,這樣,erlang就可以不用儲存每次遞迴呼叫的棧了(因為棧上沒有儲存任何狀態資訊.)函式本次呼叫的返回值就是下次呼叫的返回值.在長長的遞迴呼叫抵達最後一次返回時,可以直接把最後一次呼叫的返回值返回給第一次呼叫的呼叫者.這就是尾遞迴優化的過程.

map(f, l) -> map(f, l, ).% 適配原來的lists:map/2 的介面

尾遞迴優化

尾遞迴就是遞迴語句在函式最後執行,且無需對返回值進行進一步操作。編譯器會對這種遞迴進行優化,在進入深層遞迴時候,不是在遞迴棧進行入棧操作,而是直接覆蓋棧頂。線性遞迴與尾遞迴區別如下 線性遞迴 1 2 3 4 5 longrescuvie longn 尾遞迴 1 2 3 4 5 6 7 8 9 10 ...

尾遞迴優化

什麼是尾遞迴 尾遞迴就將遞迴呼叫寫在函式的尾部return 尾遞迴的好處 解決傳統遞迴的棧溢位問題 尾遞迴適合的業務場景 1.需要遞迴優化的函式沒有用timeout等非同步佇列進行遞迴呼叫函式自己 2.需要遞迴優化的遞迴函式的返回值不是每次都返回,而是條件性返回 尾遞迴優化後的遞迴demo meth...

erlang雜記十二 再說尾遞迴

翻了一下list模組,看的時候,突然發現,尾遞迴其實是很容易展開成迴圈的。想起讀書時剛開始學程式,c語言,一直再糾結的乙個問題,就是如何讓乙個函式返回兩個引數的結果,哈哈,不要笑我。do sth sa,sb do sth ha ta la,hb tb lb,sa,sb do sth ta,tb,ha...