當您將(+)
傳入foldr
的第一個參數時,您會隱式聲明a
與b
相同。這得到混亂,因爲我們往往會重複使用的名字,但如果我寫它一起使用的類型變量
(+) :: Num i => i -> i -> i
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr (+) :: Num i => i -> [i] -> i
相同的命名空間,其中第三線意味着i ~ a
和i ~ b
因此,通過傳遞,a ~ b
。此外,在這裏可能會更清楚地看到foldr (+)
中的第一個剩餘參數是摺疊的「初始」值,而[i]
位是我們正在壓縮,摺疊,減少的列表。
通過foldr (+) 0
更常見的名稱sum :: Num a => [a] -> a
可能更清楚。我們也有foldr (*) 1
作爲product :: Num a => a -> [a]
。
所以是的,您對foldr (+)
中累加器函數的表現的描述完全正確,但比函數更具體。例如,我們可以使用foldr
來構建一個Map
。
foldr (\(k, v) m -> Map.insert m k v) Map.empty :: Ord k => [(k, v)] -> Map k v
在這種情況下,蓄壓器功能需要我們的協會名單,並保持插入值到我們的accumulat * ING * Map
,它開始是空的。要完全徹底這裏,讓我寫出來的類型一起再次
(\(k, v) -> m -> Map.insert m k v) :: Ord k => (k, v) -> Map k v -> Map k v
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr (\(k, v) -> m -> Map.insert m k v) :: Ord k => Map k v -> [(k, v)] -> Map k v
,我們已經被迫a ~ (k, v)
和b ~ Map k v
。
作爲對此事的最終意見,這裏是foldr相似的一些暗示性的變量名
foldr _ b [] = b
foldr (<>) b (a:as) = a <> foldr f b as
定義所以你可以看到如何(<>) :: a -> b -> b
結合a
和b
類型。我們可以明確地「運行」這個定義,看看它是如何構建計算的。
foldr (+) 0 [1,2,3]
1 + (foldr (+) 0 [2,3])
1 + (2 + (foldr (+) 0 [3]))
1 + (2 + (3 + (foldr (+) 0 [])))
1 + (2 + (3 + 0))
1 + (2 + 3)
1 + 5
6
當我們使用非對稱的操作像上面Map
例子可能會更加清楚。下面我使用{{ k -> v, k -> v }}
來表示Map
,因爲它不是直接打印的。
-- inserts a single (k,v) pair into a Map
ins :: Ord k => (k, v) -> Map k v -> Map k v
ins (k, v) m = Map.insert m k v
foldr ins Map.empty [('a', 1), ('b', 2)]
ins ('a', 1) (foldr ins Map.empty [('b', 2)])
ins ('a', 1) (ins ('b', 2) (foldr ins Map.empty []))
ins ('a', 1) (ins ('b', 2) Map.empty)
ins ('a', 1) (ins ('b', 2) {{ }})
ins ('a', 1) {{ 'b' -> 2 }}
{{ 'b' -> 2, 'a' -> 1 }}
[啓示foldr相似對與foldl(或與foldl')]的可能重複(http://stackoverflow.com/questions/384797/implications-of-foldr-vs-foldl-or-foldl) –