Where to Discuss?

Local Group

More example if you wish.
With some more operators.

Explaining Monad

This tutorial/ guidance/ article is one of some parts.

The first one is overview, then some references. The last three parts is all about Example Code.


How does Monad works

I found good explanation about these three magic words (functor, applicative, and monad), using boxing analogy. I really respect the reader on how he made everything clear by putting some funny image on his article.

There’s a caveat in boxing analogy.

I did this note based on adit works. But since, it has some differences, with some additional notes also. I decide to make my own article.


Context: Maybe, Just and Nothing

Haskell has context that can be wrapped around data type. Maybe, Just and Nothing. This context approach solved common null value issue. Now a data Maybe contain Nothing or Just a value.

data Maybe a = Nothing | Just a
    deriving (Eq, Ord)

Consider open GHCI and do some Math.

>3 * 5
15

>:t 3
3 :: Num t => t

Compare with plain data above, now we can wrap data in a context.

>Just 3
Just 3

>Nothing
Nothing

>:t Just 3
Just 3 :: Num a => Maybe a

>:t Nothing
Nothing :: Maybe a

>3 * Just 5
<interactive>:20:1: error:

>Just 3 * 5
<interactive>:21:1: error:

Just is just a wrapper. Do not forget the bracket.


Bare unwrapped

Consider this Prelude using application operator and its reverse.

>(*3) 5
15

>(const 2) $ (*3) 5
2

>((const 2) . (*3)) 5
2

>5 (*3)
<interactive>:4:1: error:

>import Data.Function
Prelude Data.Function> (*3) 5 & (const 2)
2

Function is left associative. Apply left bare function to the bare value right.


Functor

How do we suppose to do simple thing with data context? Here comes the <$> operator in rescue.

>(*3) <$> (Just 5)
Just 15

>(const 2) <$> (*3) <$> (Just 5)
Just 2

>(const 2) <$> (*3) <$> [1..5]
[2,2,2,2,2]

>(id) <$> (*3) <$> [1..5]
[3,6,9,12,15]

>(Just 5) <$> (*3)
<interactive>:2:2: error:

>2 <$ [1..5]
[2,2,2,2,2]

Prelude Data.Functor> [1..5] $> 2
[2,2,2,2,2]

<$> is left associative. Apply left bare function to the wrapped context right.

Lists are functors. We can rewrite it using fmap alias, or special map for list. fmap is a generalisation of map. map is a specialization of fmap.

>(*3) <$> [1..5]
[3,6,9,12,15]

>fmap (*3) [1..5]
[3,6,9,12,15]

>map (*3) [1..5]
[3,6,9,12,15]

Function are Functor too. It looks like magic, but it is not.

>(const 2) <$> (*3) <$> Just 5
Just 2

>twofunc = (const 2) <$> (*3)

>twofunc 5
2

>twofunc Just 5
<interactive>:11:1: error:

Applicative

How about also wrapping the left function ? Here comes the <*> operator.

>Just (*3) <*> Just 5
Just 15

>pure (*3) <*> Just 5
Just 15

>Just 5 <*> Just (*3)
<interactive>:3:1: error:

<*> is also left associative. Apply left wrapped function to the context right.

>Just (*3) *> Just 5
Just 5

>Just (const 2) <*> Just (*3) <*> (Just 5)
<interactive>:20:1: error:

Using List

>[(*3), (const 2)] <*> [1..5]
[3,6,9,12,15,2,2,2,2,2]

Wrapping, in Functor and Applicative

Using boxing analogy. While <$> wrapped the value. The <*> also wrapped the function.

>(*3) <$> Just 5
Just 15

>fmap (*3) Just 5
Just 15

>Just (*3) <*> Just 5
Just 15

In context

>(*3) <$> Just 5
Just 15

>(*3) <$> Nothing
Nothing

>Just (*3) <*> Nothing
Nothing

>Nothing <*> Just 5
Nothing

>Nothing <$> Just 5
<interactive>:22:1: error:

Go further with both.

>(*) <$> (Just 3) <*> (Just 5)
Just 15

>min <$> (Just 3) <*> (Just 5)
Just 3

Bind

Apply it to bind.

> add3 int = [int + 3]

> [1, 3] >>= add3
[4,6]

And chain ‘em.

> addme int2 int1 = [int1 + int2]

> subme int2 int1 = [int1 - int2]

> [1, 3] >>= addme 3 >>= subme 2
[2,4]

> [1, 3] >>= subme 2 >>= addme 3
[2,4]

Rewrite the last sentence in multiline GHCI.

> :{
| addme int2 int1 = [int1 + int2]
| subme int2 int1 = [int1 - int2]
| 
| sequ3 :: [Int]
| sequ3 = 
|     [1, 3] 
|     >>= subme 2 
|     >>= addme 3
| :}

> print sequ3
[2,4]

And finally in do block.

> :{
| sequ4 :: [Int]
| sequ4 = do
|     x <- [1, 3] 
|     y <- subme 2 x
|     addme 3 y
| :}

> sequ4 
[2,4]

Operator Cheat Sheet

Bear in mind

  • $ function application

  • . function composition

  • <$> fmap as an infix operator. fmap.

  • <*> Applicative

  • (<$>) :: Functor f => (a -> b) -> f a -> f b

  • (<$>) = fmap

  • fmap :: Functor f => (a -> b) -> f a -> f b

  • map :: (a -> b) -> [a] -> [b]

  • (<*>) :: f (a > b) -> f a -> f b

Bear in mind.

class Monad m where
(>>=) :: m a -> (a -> m b) -> m b

instance Monad Maybe where
Nothing >>= func = Nothing
Just val >>= func = func val

More in this blog.


Further Explanation.

Meanwhile. Consider go back to adit


Thank you for Reading.