Monad is not difficult
ianen.org
ianen.org
What I like about RWH is that it builds up monads as "why you need this". You see code in its non-monadic form for a while, and then monads are introduced, and suddenly you see the same program being significantly smaller. You understand the before and after, and can begin to reason for yourself what a monad is. And it becomes abundantly clear why they are useful in Haskell -- you just saw your program shrink by 2/3s.
And a nitpick unrelated to your article -- I notice a lot of Haskell articles implement things unnaturally just to use a certain feature. This makes it hard to understand why you would actually want to use that feature. The reader skims the article, says "this is just a fold", and dismisses monads forever. (I remember reading LYAH's section on applicative functors once. All the examples do nothing, they are merely functions that technically type-check. Not a good way to learn; the real paper on applicative functors is much more approachable. But I digress.)
Some 'first principles' things are difficult to present like this because there are usually better ways to do it. The state monad is like this. Even in haskell there are more expressive (and easier to use) tools to do the same thing. In this case i think we can all accept somewhat ad hoc examples as long as they are disclaimed.
My particular purpose in writing this is to demystify monads specifically, especially for people who are casually interested in learning Haskell but unwilling to read a few hundred pages on it. RWH is great, but it doesn't explain monads until chapter 14 -- that's a lot of material a reader has to understand before they can even parse the examples.
I think 43% of the confusion about monads is due to the sheer number of "monad tutorials", each explaining two or three functions (return/bind, pure/fmap/join) with different, overly-complex analogies. (A monad is like a burrito, a monad is like a space suit, a monad is like a nuclear waste container...)
The tutorials start with some analogy, and then inevitably explain how "the list monad" and "the maybe monad" work. At the end you know that monads are like burritos, how to apply a function to every value in a list, and how to return failure from a function. But you still don't know anything about monads, or more importantly why monads.
If I were to write a monad tutorial, it would include these key points:
1) A monad is not a thing, it's a property of other things. Maybe is a thing. A list is a thing. Both are monads. (My bike is a thing. My wall is a thing. Both are blue.)
2) The abstract concept of a monad lets you reuse code. If you want to apply a function to every value of a list, you could do that without monads. If you want functions to be able to fail, and you want the failures to be composable, you could do that without monads. But what you can't do without monads is write a function like liftM2. With monads, you can turn a normal function into one that works on lists. Or that works on IO. Or that works on computations that can fail. You get to use the same function for all three types. That's the point of monads.
(Then there will be a code example:
2 + 3 --> 5
liftM2 (+) (Just 2) (Just 3) --> Just 5
liftM2 (+) Nothing (Just 3) --> Nothing
liftM2 (+) (Just 2) Nothing --> Nothing
liftM2 (+) [1,2] [3,4] --> [4,5,5,6]
liftM2 (+) readLn readLn --> 1 <ENT> 2 <ENT> --> 3
Then it all makes sense!)Isn't #2 a property of functors in general? I know I usually use <$> and <∗> rather than the liftM family because they don't limit the number of parameters.
(+) <$> (Just 2) <∗> (Just 3)
(+) <$> [1,2] <∗> [3,4]
(+) <$> readLn <∗> readLn (+) <$> (Just 2) <∗> (Just 3) <∗> (Just 5)
And it would have the same meaning as: liftM3 (+) (Just 2) (Just 3) (Just 5)
edited for formattingNote, though, that (+) only takes two parameters, so your examples won't work as written. These should be equivalent:
enumFromThenTo <$> Just 2 <*> Just 3 <*> Just 5
liftM3 enumFromThenTo (Just 2) (Just 3) (Just 5)And to be clear, for <$> and <*>, you need a Functor instance defined for you type right?
Are there benefits to using one or the other, they seem to evaluate the same, is GHC able to optimize Monad and Functor equally?
Are there benefits to using one or the other, they seem to evaluate the same, is GHC able to optimize Monad and Functor equally?
I believe there's currently no special optimizations for either case, though as I don't poke around in GHC this statement may be mistaken.The primary advantage of the application operators over liftM is that there's no liftM6, liftM7, etc; you can type <∗> as much as you want.
Regardless, the concept of "lifting" pure functions is separate from monads, which exist to enforce sequencing.
There's something about the word "monad" that just scares the hell out of people, but hopefully approaching monads from a more practical and less mathematical standpoint will make grasping them easier. They're really not that complicated.
1) Superfluous analogies
2) Usage of do-syntax rather than bind and return.
Do-syntax, which sweeps the best example of how a monad _actually_ works under the rug, used in conjunction with the phrase "inside a monad", can cause beginners over-complicate and mysticize the idea of a monad.
I have not yet read the above tutorial, but the best one I have seen to date is http://ertes.de/articles/monads.html
It's valid markup[1], and doesn't use any weird plugins. You may want to report the crash to the Chrome team.
[1] http://validator.w3.org/check?uri=http%3A%2F%2Fianen.org%2Fa...
It's an interesting enough article to open another browser though.
Haskell advocates mention pure code and monads as pros of Haskell and typical Haskell conventions. But I'm simply not willing to learn a language's full syntax to learn about some generic computing concept and how it is employed in a specific language.
If I need to learn the language you are trying to sell me to understand the concept your are trying to explain me in order to sell me the language, don't expect to get very far.