Search code examples
haskellfoldtype-signature

Fold type signature with `Foldable` type constraint


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

Solution

  • 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.