2013-07-08 57 views
1

這裏的評價是一個自定義length功能的經典第一次嘗試:嚴格整數蓄電池

length1 [] = 0 
length1 (x:xs) = 1 + length1 xs 

,這裏是一尾遞歸版本:

length2 = length2' 0 where 
    length2' n [] = n 
    length2' n (x:xs) = length2' (n+1) xs 

然而,(n+1)不會evaluted嚴格來說,Haskell會創建一個thunk,對嗎?

這是防止創建thunk的正確方法,從而迫使嚴格評估(n+1)

length3 = length3' 0 where 
    length3' n [] = n 
    length3' n (x:xs) = length3' (n+1) $! xs 

我將如何實現與seq代替$!同樣的效果?

+3

如果你打開優化,你不必做任何事情,因爲嚴格分析可以確定'n'中的定義是嚴格的。 – augustss

+0

@augustss哦,我不知道。謝謝! – fredoverflow

+0

這就是說,嚴格信息發生的具體情況取決於類型。如果你使用'Int',它肯定會起作用。 – augustss

回答

4

通常使用的方法現在編寫它將如下:

length3 :: [a] -> Int 
length3 = go 0 
    where 
     go :: Int -> [a] -> Int 
     go n []  = n 
     go n (x:xs) = n `seq` go (n+1) xs 

即,作爲在累加器嚴格的列表摺疊。 GHC產生直接翻譯到核心:

Main.$wgo :: forall a_abz. GHC.Prim.Int# -> [a_abz] -> GHC.Prim.Int# 
Main.$wgo = 
    \ (n :: GHC.Prim.Int#) (xs :: [a_abz]) -> 
    case xs of 
     [] -> n 
     _ : xs -> Main.$wgo a (GHC.Prim.+# n 1) xs 

顯示,這是在累加器裝箱(並因此嚴格)。

4

我不認爲這是非常正確的 - $!是嚴格的第二個參數,所以你只是強制列表而不是累加器。

可以使用序列像這樣得到正確的嚴格:

let n' = n + 1 in n' `seq` length3' n' xs 

我覺得更可讀的版本將使用爆炸模式(一個GHC擴展名):

length3' !n (x:xs) = ...