On my GHCi
foldr
and foldl
have this signature:
Prelude> :t foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
Prelude> :t foldl
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
What is the difference between the alternative type signature of fold, specifically t a
part?
fr :: (a -> b -> b) -> b -> [a] -> b
fl :: (b -> a -> b) -> b -> [a] -> b
The type class Foldable
defines a number of functions in addition to foldl
.
class Foldable t where
foldMap :: Monoid m => t m -> m
foldr :: (a -> b -> b) -> b -> t a -> b
foldl :: (b -> a -> b) -> b -> t a -> b
-- ...
We can define an instance of Foldable
for a type constructor t
by defining at least foldMap
or foldr
for the type. (foldl
has a default definition in terms of some of the others, so you get it for "free" as long as you supply the minimum definition).
instance Foldable [] where
foldr f b [] = b
foldr f b (x:xs) = f x : foldr f b xs
instance Foldable Maybe where
foldr f b Nothing = b
foldr f b (Just a) = f b a
The t
in the type signature just means that as long as a type constructor has a Foldable
instance for it defined, you can use foldl
with a value of the appropriate type. For example:
Prelude> foldl (+) 0 [1,2,3]
6
Prelude> foldl (+) 0 []
0
Prelude> foldl (+) 0 Nothing
0
Prelude> foldl (+) 0 (Just 3)
3
In the first two cases, we use the []
instance because the arguments corresponding to t a
are lists, meaning t
is unified with []
, written t ~ []
. In the second two, we use the Maybe
instance because the arguments corresponding to t a
are Maybe
values, so t ~ Maybe
.