假設(shè)我們需要一個(gè)string * list * list 類型的值需要處理,并返回一個(gè)去掉制定字符串的string list 類型的程序。我們?cè)趺刺幚恚?/p>
這是一個(gè)非常簡(jiǎn)單的程序,我像用這個(gè)非常簡(jiǎn)單的問(wèn)題介紹recursive 和 iterative 兩種方法。
首先定義比較字符串的函數(shù),然后定義option的類型,為recursive和iterative
fun same_string(s1 : string, s2 : string) =
s1 = s2
fun all_except_option(lst, str) =
case lst of
[] => NONE
| ls::ls' => if same_string(ls,str)
then SOME ls'
else case all_except_option(ls', str) of
NONE => NONE
| SOME xs => SOME(ls::xs)
首先我們實(shí)現(xiàn)recursive 的函數(shù)
fun get_substitutions1(str_lst_lst, str) =
case str_lst_lst of
[] => []
| ls::lst => case all_except_option(ls, str) of
NONE => get_substitutions1(lst, str)
| SOME xs => xs @ get_substitutions1(lst,str)
再看看 iterative
fun get_substitutions2(str_lst_lst, str) =
let fun aux(lst, acc) =
case lst of
[] => acc
| ls::ls' => case all_except_option(ls, str) of
NONE => aux(ls', acc)
| SOME xs => aux(ls', acc @ xs)
in
aux(str_lst_lst, [])
end
可以看到,我們最上面的遞歸形式被我在夏目按改成了尾遞歸形式,尾遞歸形式的開(kāi)銷更小。
他們?cè)趓epl中自動(dòng)推導(dǎo)的類型是這樣的
可以看到他們是一模一樣的,只是后面一種不會(huì)棧溢出,開(kāi)銷更小。
我為什么想寫這個(gè)內(nèi)容呢,我想說(shuō)的是 一個(gè)語(yǔ)言根本不需要while這種循環(huán)類的關(guān)鍵字,遞歸更加的powerful。
那么問(wèn)題來(lái)了,我的itreative是在編譯器尾遞歸優(yōu)化的情況下才做到不會(huì)導(dǎo)致棧溢出,如果編譯器十分的古老,沒(méi)有尾遞歸,這個(gè)時(shí)候你不需要循環(huán)么?
答案仍然是不需要,這是一個(gè)非常有趣的問(wèn)題,我們可以通過(guò)continuation-passing style (CPS)來(lái)解決這件事,過(guò)一段時(shí)間,我會(huì)來(lái)填這個(gè)cps的坑。