## DEV Community is a community of 623,427 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

loading...

# Functors Compose, Monads Do Not

Riccardo Odone Originally published at odone.io on ・2 min read

You can keep reading here or jump to my blog to get the full experience, including the wonderful pink, blue and white palette.

## Functor Composition

Let’s start with a refresher of `map`:

``````map :: forall a b. (a -> b) -> f a -> f b
``````

In other words, map takes a function `a -> b` and gives us a function `f a -> f b`. For that reason, we can take any two nested functors (e.g. `Array` and `Maybe`) and run a function on the nested values by putting two `map`s together:

``````v :: Array (Maybe Int)
v = [Just 1, Nothing, Just 3]

f1 :: Int -> String
f1 = show

main :: Effect Unit
main = do
logShow \$ map (map f1) v

-- [(Just "1"),Nothing,(Just "3")]
``````

## Monad Composition

This time we want to take a look at `bind`:

``````bind :: forall a b. m a -> (a -> m b) -> m b
``````

If we tried to compose the same way we did with functors, we would notice the code does not compile:

``````v :: Array (Maybe Int)
v = [Just 1, Nothing, Just 3]

f2 :: Int -> Array (Maybe String)
f2 i = [Just \$ show i]

main :: Effect Unit
main = do
logShow \$ bind v (\x -> bind x f2) -- DOES NOT COMPILE!!
``````

The problem here is in the nested `bind`:

``````bind v (\x -> bind x f2)
^ Maybe Int
^ Int -> Array (Maybe String)
``````

In fact, `Maybe Int -> (Int -> Array (Maybe String)) -> ??` is not what `bind` expects: the first argument seems to indicate that `m` is `Maybe` but the second seems to indicate that `m` is `Array`. This does not compile since the monad `m` is supposed to be the same.

To make the program compile we have to make use of a function (i.e. `maybe`) specific to the monad we are dealing with (i.e. `Maybe`):

``````main :: Effect Unit
main = do
-- logShow \$ bind v (\x -> bind x f2) -- DOES NOT COMPILE!!
logShow \$ bind v (maybe (pure Nothing) f2)
``````

Or we could use the `MaybeT` monad transformer:

``````v2 :: MaybeT Array Int
v2 = MaybeT [Just 1, Nothing, Just 3]

f3 :: Int -> MaybeT Array String
f3 i = MaybeT [Just \$ show i]

main :: Effect Unit
main = do
--logShow \$ bind v (\x -> bind x f2)
logShow \$ bind v (maybe [Nothing] f2)
logShow \$ runMaybeT \$ bind v2 f3
``````

## Outro

I’ve blatantly copied the content of this blog post out of a talk by Tony Morris. So be sure to check the original stuff out!

Get the latest content via email from me personally. Reply with your thoughts. Let's learn from each other. Subscribe to my PinkLetter!

## Discussion (2)

Anton
``````map :: forall a b. (a -> b) -> f a -> f b

``````

What is "forall a b.". When I check map in the ghci it just gives me

``````

map :: (a -> b) -> f a -> f b
``````
Riccardo Odone

The snippets in this posts are written in PureScript. My bad for not making it clear, sorry!

If you are curious you can find the answer to your question in the "Differences from Haskell" docs in the PureScript docs repo. The punch line is the one that follows:

Polymorphic functions in PureScript require an explicit forall to declare type variables before using them.