Hacker News new | ask | show | jobs
by jneen 4918 days ago
What I wish someone had explained to me earlier was that Monads are an abstraction level up from most things you ever program with. Learn specific ones, and the general picture will start to make more sense. Avoid the IO monad until you understand, in order:

+ the List monad (probably the easiest for python people, since it's very similar to list comprehensions)

+ the Maybe monad (kind of a degenerate case)

+ the State monad

And it's much easier if you do it in Haskell, trust me. "Learn You A Haskell For Great Good" is a nice easy intro to the basics.

2 comments

Most information on Monads start out with IO, which I agree isn't helpful. I found one that explained it with Maybe and Either, and that was where I began to understand it.

I think Maybe is the easiest to grasp for people who work in procedural languages, since there's a very common idiom of returning a nil object if some operation doesn't succeed. You can look at Maybe and see immediately; "oh this is like a type-safe version of that". Then from there, Either makes since almost instantly, and you can sneak in List and some others before they realize they shouldn't be able to understand it :)

Since I like your order of Monadic instruction, do you perhaps have a preferred starting point for learning Arrows? I can see that it's a way to compose sequences of computation, but I don't get what problems they solve that are difficult to solve with other methods.

This is the part where I admit that I don't quite get Arrows. Anyone else?
Anyone else who doesn't get arrows? Count me in! I wish i understood this comic's joke: http://ro-che.info/ccc/12.html :(
There was a blog post that came out around that time in which it was claimed that arrows are easy to understand because they're just functions. There was a lot of backlash, and this comic is trying to point out that the reasoning behind it is backwards. Every function is an arrow, but not every arrow is a function. I believe the blog post in question is here:

http://blog.romanandreg.com/post/2755301358/on-how-haskells-...

That's about the limit of my comprehension of arrows. When you see a type (Arrow arr) => arr a b, you should read it as "an arrow from a to b", just like a function (a -> b) can be read "a function from a to b". But an arrow can encompass a monad, a function a -> m b is also an arrow, a Kleisli arrow with type Kleisli m a b. So this means you can use the arrow composition functions with normal functions as well as monadic functions, as well as arrows of other types which need not be functions at all.

Beyond that, all I know is that arrows provide composition functions that allow you to build a digraph of computations where inputs come in, get split off, passed through other arrows and recombined in interesting ways, and there is an arrow syntax which is so convoluted I've never been able to understand the relationship between it and the fundamental arrow combinators. I have never run into a situation where knowing anything about arrows was useful, other than because (&&&) is a neat combinator if you're want tuples. Practice doesn't seem to have caught up to the theory here, and things like applicative functors, which are simpler than monads in some sense, are a lot more useful than arrows, which are more complex. This blog post illustrates a case where arrows were handy, but he winds up using applicative functors in the end also:

http://jaspervdj.be/posts/2012-01-14-monads-arrows-build-sys...

It's a curious thing about functional programming that often what's simpler in theory (monoids, functors) turn out to be more useful in complex situations in the real world than what's more complex in theory.

One last note, I wrote a blog post about this in 2007 with FizzBuzz. Forgive me if it's horrible; I haven't given it much thought since, but here it is:

http://old.storytotell.org/blog/2007/04/08/haskell-arrows.ht...

Thanks for the link, I hadn't seen the second one. I felt like I almost understood what they are for, and the constructors for the arrow datatype aren't very cryptic, but then it hits the code examples, which has stuff like

    y <- readFileA "unicorns.txt" -< ()
and it's unlike anything I'm used to. I'd love to find a post that described the utility of arrows as well as his did and then maybe having a middle step where they are used without the arcane symbols, and then finally with the arcane symbols.

Your post was very clear (although your code blocks have a tiny font on my computer for some reason). The &&& and >>> combinators make sense, especially with your diagram... but in the fizzbuzz case I don't get why it's preferable to have the arrow over something like

    fizzbuzz x = combine (three x) (five x)
Although maybe it's just a case of making it simple to compose functions when there are tens of inputs or something, so the simple case wouldn't really demonstrate anything like that.
I think we're on the same page not seeing a real use for them. :)
>+ the Maybe monad (kind of a degenerate case)

Hey. Hey. heyyyyy.

I've used bind + maybe monad 'ish stuff in Python to clean up code previously littered with redundant if checks.

He probably means its a degenerate case of the list monad. Which is a useful way to look at it: a Maybe value is like a list of length at most 1.

You can also look at it as a degenerate case of Either. (That is, Maybe a ~ Either () a.)

This is "degenerate" in the mathematical sense, much the same way you can think of a point as a degenerate circle.

Yes, the point is that it's just about the simplest Monad implementation that actually does something useful.

I'd observe in my code that I rarely have an enormous do block using Maybe; instead what I see a lot is use of the monadic interface to tie things together that would normally be a lot of if blocks, all on one line into one expression. You start missing that in other languages real fast. Also the Applicative instance is often quite useful, allowing you to easily tie together several things that return Maybes into a call of some sort that does the right thing if one of them is a Nothing, almost "free" from a syntax point of view.

Haha, yeah, I meant "degenerate" in the mathematical sense. Totally useful, but in explaining it you're going to get a lot of "well, it's trivial in this case because...", which isn't that helpful if you don't yet understand the underlying concepts :)