this repo has no description
at main 5.1 kB view raw
1* Monads 2Monads are a natural extension of applicative functors and with them we're concerned with this: 3if you have a value with a context, =m a=, how do you apply to it a function that takes a normal =a= and returns a value with a context? 4That is, how do you apply a function of type =a -> m b= to a value of type =m a=? 5So essentially, we will want this function: 6 7#+begin_src haskell 8(>>=) :: (Monad m) => m a -> (a -> m b) -> m b 9#+end_src 10 11If we have a fancy values and a function that takes a normal value but returns a fancy value, how do we feed that fancy value into the function? 12This is the main question that we will concern ourselves when dealing with monads. 13We write =m a= instead of =f a= because the =m= stands for =Monad=, but monads are just applicative functors that support =>>==. The =>>== function is pronounced as /bind/. 14 15Much to no one's surprise, =Maybe= is a monad, so let's explore it a bit more and see if we can combine it with what we know about monads. 16 17A value of type =Maybe a= represents a value of type =a= with the context of possible failure attached. 18When we looked at =Maybe= as a functor, we saw that if we want to =fmap= a function over it, it gets mapped over the insides if it's a =Just= value, otherwise the =Nothing= is kept because there's nothing to map it over. 19Like this: 20 21#+begin_src haskell 22fmap (++"!") (Just "windom") 23#+end_src 24 25#+RESULTS: 26: Just "windom!" 27 28#+begin_src haskell 29fmap (++"!") Nothing 30#+end_src 31 32#+RESULTS: 33: Nothing 34 35As an applicative functor, it functions simirlaly. However, applicatives also have the function wrapped. 36=Maybe= is an applicative functor in such a way that when we use =<*>= to apply a function inside a =Maybe= to a value that's inside a =Maybe=, they both have to be =Just= values for the result to be a =Just= value, otherwise the result is =Nothing=. 37 38#+begin_src haskell 39Just (+3) <*> Just 3 40#+end_src 41 42#+RESULTS: 43: Just 6 44 45#+begin_src haskell 46Nothing <*> Just "greed" 47#+end_src 48 49#+RESULTS: 50: Nothing 51 52When we use the applicative style to have normal functions act on =Maybe= values, it's similar. 53All the values have to be =Just= values, otherwise it's all for =Nothing=! 54 55#+begin_src haskell 56max <$> Just 3 <*> Just 6 57#+end_src 58 59#+RESULTS: 60: Just 6 61 62#+begin_src haskell 63max <$> Just 3 <*> Nothing 64#+end_src 65 66#+RESULTS: 67: Nothing 68 69And now, let's think about how we would do =>>== for =Maybe=. Like we said, =>>== takes a monadic value, and a function that takes a normal value and returns a monadic value and manages to apply that function to the monadic value. 70How does it do that, if the function takes a normal value? Well, to do that, it has to take into account the context of that monadic value. 71 72In this case, =>>== would take a =Maybe a= value and a function of type =a -> Maybe b= and somehow apply the function to the =Maybe a=. 73To figure out how it does that, we can use the intuition that we have from =Maybe= being an applicative functor. 74Let's say that we have a function =\x -> Just (x+1)=. It takes a number, adds =1= to it and wraps it in a =Just=. 75 76#+begin_src haskell 77(\x -> Just (x+1)) 1 78#+end_src 79 80#+RESULTS: 81: Just 2 82 83Now here's the kicker: how do we feed a =Maybe= value to this function? 84If we think about how =Maybe= acts as an applicative functor, answering this is pretty easy, if we feed it a =Just= value, take what's inside the =Just= and apply the function to it. 85If give it a =Nothing=, then we're left with a function but =Nothing= to apply it to. 86In this case, let's just do what we did before and say that the result is =Nothing=. 87 88Instead of calling it =>>==, let's call it =applyMaybe= for now. 89It takes a =Maybe a= and a function that returns a =Maybe b= and manages to apply that function to the =Maybe a=. 90Here it is in code: 91 92#+begin_src haskell 93 :{ 94 applyMaybe :: Maybe a -> (a -> Maybe b) -> Maybe b 95 applyMaybe Nothing f = Nothing 96 applyMaybe (Just x) f = f x 97 :} 98#+end_src 99 100#+RESULTS: 101 102Okay, now let's play with it for a bit. 103We'll use it as an infix function so that the =Maybe= values is on the left side and the function on the right: 104 105#+begin_src haskell 106Just 3 `applyMaybe` \x -> Just (x+1) 107#+end_src 108 109#+RESULTS: 110: Just 4 111 112#+begin_src haskell 113Nothing `applyMaybe` \x -> Just (x+1) 114#+end_src 115 116#+RESULTS: 117: Nothing 118 119In the above example, we see that when we used =applyMaybe= with a =Just= value and a function simply got applied to the value inside the =Just=. When we tried to use it with a =Nothing=, the whole result was =Nothing=. 120What about if the function returns a =Nothing=? Let's see: 121 122#+begin_src haskell 123Just 3 `applyMaybe` \x -> if x > 2 then Just x else Nothing 124#+end_src 125 126#+RESULTS: 127: Just 3 128 129#+begin_src haskell 130Just 1 `applyMaybe` \x -> if x > 2 then Just x else Nothing 131#+end_src 132 133#+RESULTS: 134: Nothing 135 136Just what we expected. If the monadic value on the left is a =Nothing=, the whole thing is =Nothing=. 137And if the function on the right returns a =Nothing=, the result is =Nothing= again. 138This is very similar to when we used =Maybe= as an applicative and we got a =Nothing= result if somewhere in these was a =Nothing=.