我從Foldr Foldl Foldl'讀取,foldl'
由於嚴格性屬性對長有限列表更有效。我知道它不適合無限列表。性能增益實現concatMap與foldl'爲有限列表?
因此,我限制只有長有限列表的比較。
concatMap
concatMap
使用foldr
,這使得它的懶惰實現。然而,根據這篇文章,使用它與長期有限的名單將建立一個長期未減少的鏈。
concatMap :: Foldable t => (a -> [b]) -> t a -> [b]
concatMap f xs = build (\c n -> foldr (\x b -> foldr c b (f x)) n xs)
因此我拿出來與使用foldl'
以下實現。
concatMap' :: Foldable t => (a -> [b]) -> t a -> [b]
concatMap' f = reverse . foldl' (\acc x -> f x ++ acc) []
測試出來
我有構建以下兩個功能來測試性能。
lastA = last . concatMap (: []) $ [1..10000]
lastB = last . concatMap' (: []) $ [1..10000]
但是,我對結果感到震驚。
lastA:
(0.23 secs, 184,071,944 bytes)
(0.24 secs, 184,074,376 bytes)
(0.24 secs, 184,071,048 bytes)
(0.24 secs, 184,074,376 bytes)
(0.25 secs, 184,075,216 bytes)
lastB:
(0.81 secs, 224,075,080 bytes)
(0.76 secs, 224,074,504 bytes)
(0.78 secs, 224,072,888 bytes)
(0.84 secs, 224,073,736 bytes)
(0.79 secs, 224,074,064 bytes)
後續問題
concatMap
outcompetes我在這兩個時間和內存concatMap'
。我不知道我在我的concatMap'
實施中犯了什麼錯誤。
因此,我懷疑陳述foldl'
的好處的文章。
是否有任何
concatMap
黑魔法使它如此高效?確實
foldl'
對於長有限表更有效嗎?使用帶有長有限列表的
foldr
是否真的會建立一個長未減少的鏈並影響性能?
那麼你使用在* O(n)*中運行的'++',其中* n *是左列表的大小......所以你通常要避免這種情況(因爲你要定義一個concat on一個concat concat ...) –
@Willem感謝您的及時迴應。對於'concatMap',我該如何避免'++'?而且,測試用例的'f x'大小爲1。 – Gavin
''foldl''很好,如果你用一個嚴格的函數從一個種子構建一個很好的嚴格數據類型來更新 - 就像一個'Int''開始於'Int'種子使用'(+)'來取最簡單的例。如果從列表構造一個列表或其他懶惰結構,'foldr'將會更加自然。 – Michael