簡體   English   中英

理解Haskell seq

[英]Understanding Haskell seq

我是一個Haskell新手,在理解seq遇到了問題,我在下面的例子中對此進行了總結。

以下是相同(愚蠢)函數的2個實現。 該函數采用正int n並返回元組(n,n) 通過使用具有元組累加器的輔助函數從(0,0)向上計數來產生答案。 為了避免構建一個龐大的thunk我使用seq來使累加器嚴格。

testSeq1中,元組的內容是嚴格的,而在testSeq2 ,元組本身是嚴格的。 我認為這兩個實現將執行相同的操作。 但實際上,'使用中的總內存'對於testSeq1僅為1MB,而對於testSeq2則為testSeq2 (當使用n = 1000000進行測試時)。

testSeq2什么問題?

testSeq1 :: Int -> (Int,Int)
testSeq1 n = impl n (0,0) where
    impl 0 (a,b) = (a,b)
    impl i (a,b) = seq a $ seq b $ impl (i-1) (a+1, b+1)

testSeq2 :: Int -> (Int,Int)
testSeq2 n = impl n (0,0) where
    impl 0 acc = acc
    impl i acc = seq acc $ impl (i-1) ((fst acc)+1, (snd acc)+1)

seq ing一個元組只會強制它被評估,以暴露它的元組構造函數,但不會評估它的組件​​。

那是,

let pair = id (1+1, 2+2)
in seq pair $ ...

將應用id並生成(_thunk1, _thunk2) ,其中_thunk指向添加,此時不進行評估。

在你的第二個例子中,你強制累加器acc ,而不是它的組件,因此仍然會積累一些大的thunk。

您可以使用所謂的評估策略,例如:

evalPair :: (a,b) -> ()
evalPair (a,b) = seq a $ seq b ()

testSeq2 :: Int -> (Int,Int)
testSeq2 n = impl n (0,0) where
impl 0 acc = acc
impl i acc = seq (evalPair acc) $ impl (i-1) ((fst acc)+1, (snd acc)+1)

但是, testSeq1是一種更簡單的方法。

作為另一種選擇,使用嚴格的元組 這樣的元組永遠不會有組件的thunk,但只評估結果。 強制tuple構造函數將強制組件,如您所料。

import Data.Strict.Tuple

testSeq2 :: Int -> Pair Int Int
testSeq2 n = impl n (0 :!: 0) where
impl 0 acc = acc
impl i acc = seq acc $ impl (i-1) ((fst acc + 1) :!: (snd acc + 1))

seq只強制對其第一個參數進行淺層評估。 你可以看到這兩個例子:

errorTuple :: (Int, Int)
errorTuple = undefined

errorTupleContents :: (Int, Int)
errorTupleContents = (undefined, undefined)

case1 = errorTuple `seq` (1, 1)
case2 = errorTupleContents `seq` (1, 1)

case1將因undefined錯誤而失敗,因為seq試圖強制評估errorTuple ,這是undefined ,但是, case2不會,因為元組構造函數被計算並返回其內容未被評估的元組。 如果他們被評估,他們將是undefined

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM