[英]Lazy Evaluation and Strict Evaluation Haskell
我了解什么是惰性評估,以及它的工作原理和優勢,但是您能否解釋一下Haskell到底進行了什么嚴格評估? 我似乎找不到太多有關它的信息,因為惰性評估是最著名的。
他們每個人比另一個人有什么好處。 何時實際使用嚴格評估?
在Haskell中,嚴謹性以幾種方式發生,
首先,定義。 當且僅當函數的參數a
不終止且fa
也不終止時,函數才是嚴格的。 Nonstrict(有時稱為lazy)與之相反。
您可以使用模式匹配來嚴格要求參數
-- strict
foo True = 1
foo False = 1
-- vs
foo _ = 1
由於我們不需要評估參數,因此我們可以傳遞類似foo (let x = x in x)
,它仍然只返回1
。 但是,對於第一個函數,該函數需要查看輸入的值是多少,以便它可以運行適當的分支,因此非常嚴格。
如果由於某種原因無法進行模式匹配,則可以使用一個名為seq :: a -> b -> b
的魔術函數。 seq
基本上規定,每當對其求值時,它將對a
稱為弱頭范式的求值。
您可能想知道為什么值得這樣做。 讓我們考慮一個案例研究, foldl
vs foldl'
。 foldl
在它的累加器中很懶,因此實現了類似
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f accum [] = acuum
foldl f accum (x:xs) = foldl (f accum x) xs
請注意,由於我們對accum
從未嚴格要求,所以我們將建立大量的thunk, f (f (f (f (f (f ... accum)))..)))
前景不佳,因為這確實會導致內存問題
*> foldl (+) 0 [1..500000000]
*** error: stack overflow
現在更好的是,如果我們在每個步驟中使用seq
強制評估
foldl' :: (a -> b -> a) -> a -> [b] -> a
foldl' f accum [] = accum
foldl' f accum (x:xs) = let accum' = f accum x
in accum' `seq` foldl' f accum' xs
現在,我們在每個步驟中強制對accum
進行評估,以使其更快。 這將使foldl'
在恆定的空間中運行,而不是像foldl
那樣的stackoverflow。
現在seq
僅將其值評估為弱頭范式,有時我們希望將其完全評估為范式。 為此,我們可以使用庫/類型類
import Control.DeepSeq -- a library on hackage
deepseq :: NFData a => a -> b -> a
這會強制對a
進行全面評估,
*> [1, 2, error "Explode"] `seq` 1
1
*> [1, 2, error "Explode"] `deepseq` 1
error: Explode
*> undefined `seq` 1
error: undefined
*> undefined `deepseq` 1
error undefined
因此,這充分評估了其論點。 例如,這對於並行編程非常有用,在並行編程中,您希望在某個內核上的某些內容被發送回主線程之前對其進行完全評估,否則,您將創建一個thunk,而所有實際計算仍將是順序的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.