More example if you wish.
With some more operators.
Explaining Monad
This tutorial/ guidance/ article is one of some parts.
-
Overview: Summary.
-
References: About Monad.
-
Examining Bind: Bind »= operator. Hello World Example.
-
Examining Bind: <*> and <$> operators. Personal Notes. Example using Number.
-
Monadic Operator: Fish >=> operator.
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.