Search code examples
haskellfunctormap-function

map Functor over a list in Haskell


bit confused. fmap sounds like it can map all over a list of Maybe's, but I can't get it to work if I use e.g. fApplyFunctor = (+1) <$> [Just 1, Just 2].

What seems to work perfectly fine is: map ((+1) <$>) [Just 1, Just 2, Just 3]. This seems to be overkill in that sense that I recall fmap could do that by itself already...


Solution

  • No fmap means you can map over an arbitrary Functor type (well think about it for now as a collection), but you only do this one "functor level" deep. In case you fmap with a list, it is exactly equivalent to map.

    fmap however is defined over all sorts of Functors, like lists, Maybes, etc. Here you can thus fmap in the fmap to map over two levels:

    fApplyFunctor = fmap (fmap (+1)) [Just 1, Just 2]

    This will then result in:

    Prelude> fmap (fmap (+1)) [Just 1, Just 2]
    [Just 2,Just 3]
    Prelude> (fmap (+1)) <$> [Just 1, Just 2]
    [Just 2,Just 3]
    Prelude> ((+1) <$>) <$> [Just 1, Just 2]
    [Just 2,Just 3]
    

    EDIT: like @DanielWagner says, there exists a data type Compose which works over two (or more if you cascade) Functors and thus allows us to fmap two levels deep. This is implemented like:

    newtype Compose f g a = Compose { getCompose :: f (g a) }
    
    instance (Functor f, Functor g) => Functor (Compose f g) where
        fmap f (Compose x) = Compose (fmap (fmap f) x)
    

    so here we again perform an fmap on two levels:

    Prelude Data.Functor.Compose> getCompose ((+1) <$> Compose [Just 1, Just 2])
    [Just 2,Just 3]
    

    But as you see it requires some syntax to first wrap the data in a Compose, and then to later "unwrap" it out of the Compose, so this requires some extra work as well.