Learn and Discover Open Source with Daily Genuine Experience. From Coding, Front End, Back End, Database, and Static Site Generator.
 
 
code  


More example if you wish.
With some more operators.
Information: This article is my personal note.

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.