簡體   English   中英

concatMap f xs和concat $ map f xs之間的區別?

[英]Difference between concatMap f xs and concat $ map f xs?

據推測,他們做同樣的事情, concatMap f xsconcat $ map f xs 為什么我會選擇一個而不是另一個?

我想這可能是一個優化。 如果是這樣,GHC 7.8仍然如此嗎?

這是你懷疑concatMap f xs = concat (map f xs) 因此,為了正確起見,您應該將它們視為可互換的。 不過,我們可以檢查他們的定義以了解更多信息。

concatMap               :: (a -> [b]) -> [a] -> [b]
concatMap f             =  foldr ((++) . f) []

concat :: [[a]] -> [a]
concat = foldr (++) []

特別是,這意味着concat . map f concat . map f擴展為foldr (++) [] . map f foldr (++) [] . map f 現在使用被稱為fold通用屬性”的東西,我們可以看到foldr gz . map f = foldr (g . f) z foldr gz . map f = foldr (g . f) z代表任何( gzf ),例如我們上面使用的選擇( (++)f[] )。 這表明concatMap f = concat . map f concatMap f = concat . map f就像我們想要的那樣。[0]

那他們為什么定義不同呢? 因為foldr ((++) . f) []總是比foldr (++) [] . map ffoldr (++) [] . map f foldr (++) [] . map f因為,在一個真正的病理情況下,后者表明兩個單獨的遞歸。 由於懶惰,不太可能執行兩次遞歸,那么是什么給出了?

真正的原因是,有更復雜的融合的法律提供給編譯器,如那些結合了兩種順序foldr秒或它定義之間的相互作用foldrunfoldr 使用它們有點挑剔,因為它們依賴於能夠查看代碼片段的表面語法並檢測可能的簡化。 許多工作都是為了不斷解決融合法。

但我們可以做的一件事是鼓勵人們使用預先應用優化法則的高階組合器。 foldr (++) [] . map f foldr (++) [] . map f永遠不會比foldr ((++) . f) []更快foldr ((++) . f) []我們可以采用捷徑並預先應用普遍的法律簡化。 這將提高融合法在其他地方解雇的可能性,以最佳地優化列表生產管道。

[0]為什么這項法律有效? 大致上, foldr的普遍定律指出,如果你有任何函數q使得q [] = zq (a:as) = fa (q as)那么q 必須是並且 foldr fz 因為q = foldr gz . map f q = foldr gz . map f可以顯示為q [] = zq (a:as) = g (fa) (q as)然后它必須像我們想要的那樣折疊像折疊foldr (g . f) z

暫無
暫無

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

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