作者noctem (noctem)
看板PLT
標題Re: [心得] lazy evaluation
時間Mon Mar 5 14:14:39 2007
※ 引述《godfat (godfat 真常)》之銘言:
: 推 ephesians:lazy是用來節省計算成本,結果仍浪費成本啊! XD 03/02 06:45
: 能越早做 eval 或 binding 執行效率當然會越高,我覺得大部份的情況下
: 還是需要 eager eval, 只有很少數是真的需要用 lazy eval. 當然,這是
: 指使用 imperative 之形式的話,funational 又是另一回事了 @@
我記得有研究分析過真正使用 non-strictness(*) 的時機到底有
多少,結論是不多,所以不值得(像 Haskell 這樣)把它當作
default. 不過我可能記錯。
(*) 嚴格說起來,lazy evaluation 只是一種實作 non-strict
語意的方法之一(還有其他的方法)。不過 lazy evaluation 這個詞念起來比較
印象深刻,所以實際上常常混用。
我之前不知道 D 這個語言。看前一篇的描述,似乎就頗像是把 eager
當作 default, 需要 lazy 的時候再特別宣告一下。
對我來說,我是已經很習慣 laziness 了,並不知道自己真的是否
有用到,只覺得如果沒有會怪怪的。
* * *
關於 log 的例子指出了重要的一點: non-strictness 提供了另一種
模組化的可能。像 log 如果不是 non-strict 的,就沒法獨立出來變
成一個可重用的函數。
「Lazy evaluation 省計算」這件事情其實是個誤解/誤導。舉個例子,
如果要算 n 階層,我們可以先產生 [1,2,3...,n] 的串列,然後把它
乘起來;要產生 [1,2,3..n] 這個串列,可以先產生一個從 1 開始
的無限長串列(寫成 [1..] )然後取前面 n 個。所以可以這麼做:
foldr (*) 1 (take n [1..])
其中 take n 取串列的前面 n 個元素, foldr (*) 1 把他們
乘起來。可是先產生一個長串列、再截一段出來、再乘起來,不是很
費工又耗記憶體嗎?我們說,沒關係,在 lazy evaluation 之下,
只有使用到的地方才會去計算,所以其實這個程式用的是 constant
space, 而且也沒有真的去產生無限長的串列。
所以 lazy evaluation 省時間/空間?其實沒有這回事,因為所謂
省是要看和誰比。如果今天是用一個 eager 的語言,程式根本就
不會這樣寫。Lazy evaluation 「省」出來的結果,其實和一個
eager 程式本來會寫成的樣子是一樣的。而且 laziness 還會有些
overhead.
那 laziness (或 non-strictness) 的好處是什麼?其一是這些
take, foldr, map 等等函數都是可以在很多場合下重複使用的元件。
Non-strictness 增加了模組化的可能。其二是我們能表達「無限長
的串列」這種東西。
論效率的話,目前的 lazy 語言還是比較難實作得有效率。有人
提出一種所謂的「lenient evaluation」,認為是 lazy 與 eager
之間折衷的好方法。不過是否真如此就還需要研究了。
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.109.20.217
1F:推 jeunder:請問為何能夠有 "增加模組化的可能" ? 03/06 23:51