[英]Laziness in recursive function composition
我試圖理解 Haskell 的惰性求值,並在GHCi
進行了以下嘗試
GHCi, version 8.0.2: http://www.haskell.org/ghc/ :? for help
Prelude> :set +m
Prelude> let iterateUntilError1 :: (a->a) -> (a->a)
Prelude| iterateUntilError1 f = (iterateUntilError1 f) . f
Prelude|
Prelude> let iterateUntilError2 :: (a->a) -> (a->a)
Prelude| iterateUntilError2 f = \x -> (iterateUntilError2 f) . f $ x
Prelude|
Prelude> let iterateUntilError3 :: (a->a) -> (a->a)
Prelude| iterateUntilError3 f = \x -> (iterateUntilError3 f) . f $! x
Prelude|
Prelude> let iterateUntilError4 x = foldl1 (.) (repeat (($!) x))
Prelude> iterateUntilError3 tail [1..5]
*** Exception: Prelude.tail: empty list
Prelude> iterate tail [1..5]
[[1,2,3,4,5],[2,3,4,5],[3,4,5],[4,5],[5],[],*** Exception: Prelude.tail: empty list
在提供的 4 個版本中,只有iterateUntilError3
按預期工作,其他 3 個版本進入無限循環,必須通過Ctrl + C停止。 我不太明白為什么其他三個版本在這種情況下不起作用。
相關的問題懶惰和函數組合(haskell,erlang)似乎沒有解決這個問題中提出的問題。
讓我們從iterateUntilError1
開始。 如果您嘗試評估
iterateUntilError1 tail [1..5] =
展開iterateUntilError1
定義:
((iterateUntilError1 tail) . tail) [1..5] =
擴展定義.
:
(iterateUntilError1 tail) (tail [1..5]) =
等等,我們iterateUntilError1 tail
了!
((iterateUntilError1 tail) . tail) (tail [1..5]) =
(iterateUntilError1 tail) (tail (tail [1..5]))
等等。
使用iterateUntilError3
您有(插入一些額外的括號以使優先級更清晰)
iterateUntilError3 tail [1..5] =
((iterateUntilError3 tail) . tail) $! [1..5] =
((iterateUntilError3 tail) . tail) (1:[2..5]) =
iterateUntilError3 tail (tail (1:[2..5])) =
(iterateUntilError3 tail . tail) $! (tail (1:[2..5])) =
(iterateUntilError3 tail . tail) (2:[3..5]) = ...
所以它最終會出錯。
使用iterateUntilError2
,您有類似的評估,直到最后一行 where $!
強制tail
減少直到獲得構造函數,而$
不會:
(iterateUntilError2 tail . tail) $ (tail [1..5]) =
(iterateUntilError2 tail . tail) (tail [1..5]) =
(iterateUntilError2 tail) (tail (tail [1..5])) = ...
最后(為了簡單起見,使用tail_
for (tail $!)
):
iterateUntilError4 tail [1..5] =
foldl1 (.) (repeat tail_) [1..5] =
foldl (.) tail_ (repeat tail_) [1..5] =
foldl (.) (tail_ . tail_) (repeat tail_) [1..5] =
foldl (.) (tail_ . tail_ . tail_) (repeat tail_) [1..5] = ...
(對於這個我沒有遵循實際的定義,但我認為這個想法應該仍然是正確的)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.