Table of Content
These are Haskell related articles.
How Haskell Syntax can Make Your Code CleanerLoop in Haskell With Map, Overview
Loop in Haskell With Map, Part One
Loop in Haskell With Map, Part Two
Loop in Haskell With Map, Part Three
Explaining Monad: Overview
Explaining Monad: References
Examining Bind in Haskell: Hello World
Examining Bind in Haskell: Example using Number
Examining Bind in Haskell: Do Notation
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.