Re:Functors, Applicatives, and Monads in Plain English
by jstimpfle on Friday April 22, 2016 @06:50PM
(#11553078)
I think he specifically addressed people who know Swift's flatMap. I don't, but here's more if you know a little Haskell.
Suppose you have a function of type (String -> IO ()). For example, putStrLn. It takes a String and converts it into a real world computation (printing the string) of type (IO ()).
That's nice, but what if the input string is not purely there but only "hidden" in another IO computation? For example, it could come from getLine which has type (IO String).
Now we have some (IO String) and some (String -> IO ()) and would like to compose these, i.e. print out again what was input. But they are not strictly compatible since the left thing is in IO context (i.e., computed at runtime).
Since IO is a functor we can do (fmap putStrLn getLine) which is of type (IO (IO ())) if you do the math. This is a computation which at runtime computes another computation (putStrLn applied to the computed string).
The thing that Monad gives you is to merge layers. In the case of IO, that is to actually execute the dynamically computed computation. Formally, merging (IO (IO ())) to (IO ()). Or for any type a, merging (IO (IO a)) to (IO a).
The merging method is called join and is the cleanest way to explain what makes a monad. However in haskell the Monad instances are unfortunately given by (>>=) which is a more complicated way to define the same thing. There is also join in Haskell but it's defined in terms of (>>=).
Suppose you have a function of type (String -> IO ()). For example, putStrLn. It takes a String and converts it into a real world computation (printing the string) of type (IO ()).
That's nice, but what if the input string is not purely there but only "hidden" in another IO computation? For example, it could come from getLine which has type (IO String).
Now we have some (IO String) and some (String -> IO ()) and would like to compose these, i.e. print out again what was input. But they are not strictly compatible since the left thing is in IO context (i.e., computed at runtime).
Since IO is a functor we can do (fmap putStrLn getLine) which is of type (IO (IO ())) if you do the math. This is a computation which at runtime computes another computation (putStrLn applied to the computed string).
The thing that Monad gives you is to merge layers. In the case of IO, that is to actually execute the dynamically computed computation. Formally, merging (IO (IO ())) to (IO ()). Or for any type a, merging (IO (IO a)) to (IO a).
The merging method is called join and is the cleanest way to explain what makes a monad. However in haskell the Monad instances are unfortunately given by (>>=) which is a more complicated way to define the same thing. There is also join in Haskell but it's defined in terms of (>>=).