←back to thread

A list is a monad

(alexyorke.github.io)
153 points polygot | 2 comments | | HN request time: 0s | source
Show context
brooke2k ◴[] No.44445948[source]
As far as monad tutorials go, this one seems quite good. I like the categorization of monads between "containers" and "recipes".

However, I personally think that monad tutorials tend to give people the wrong impression and leave them more confused than they were before, because they focus on the wrong thing.

A monad is not a complex concept, at all. IMO a more useful way to present the topic would be with one separate lesson for every common monad instance. Start with Maybe, then IO, then maybe State and List, and so on... because ultimately, every instance of a Monad works very differently. That's why the pattern is so useful in the first place, because it applies to so many places. (Note: this is a criticism of monad tutorials in general, not this one in particular, which seems to do a decent job on this front).

In my experience, people new to Haskell focus way too much on getting the "a-ha" moment for monads in general, when really you want a bunch of separate "a-ha" moments as you realize how each instance of a monad takes advantage of the pattern differently.

I also tend to think that monads are best demonstrated in Haskell rather than in other languages, if only because the notation is so much less clunky. That may just be me though. (EDIT: well, also because almost no other languages have typeclasses, so you have to approximate it with interfaces/traits/etc)

Also FYI: in part 2, the code examples have extra newlines in between every line, which makes it hard to read (I'm on firefox, if that matters).

replies(15): >>44446327 #>>44446377 #>>44446564 #>>44446988 #>>44447713 #>>44448118 #>>44448413 #>>44449093 #>>44449627 #>>44449895 #>>44450873 #>>44450887 #>>44451012 #>>44451851 #>>44458827 #
pdhborges ◴[] No.44446327[source]
If all monad instances work differently what is the value of the Monad interface? What kind of usefull generic code can one write against the Monad interface.

Related: https://buttondown.com/j2kun/archive/weak-and-strong-algebra...

replies(11): >>44446453 #>>44446472 #>>44446556 #>>44446586 #>>44446781 #>>44446882 #>>44447360 #>>44448151 #>>44448170 #>>44450818 #>>44462125 #
ChadNauseam ◴[] No.44446453[source]
Lots of useful generic code. MapM is a version of `map` that works with any Monad, `sequence` works with any monad, and so on. These are used very frequently.

But the bigger benefit is when syntax sugar like `do` notation comes in. Because it works for any Monad, people can write their own Monads and take advantage of the syntax sugar. That leads to an explosion of creativity unavailable to languages who "lock down" their syntax sugar to just what the language designers intended. In other words, what requires a change to other languages can often be a library in Haskell.

replies(1): >>44447334 #
bjourne ◴[] No.44447334{3}[source]
What can a Haskell monad do that a Python class cannot? 99% of all monads I've seen only facilitate local state manipulation.
replies(4): >>44447669 #>>44447962 #>>44448127 #>>44454006 #
tome ◴[] No.44448127{4}[source]
It's not about what a monad can do, it's about a property of the language: referential transparency. Haskell has referential transparency, Python doesn't. That's a technical condition but here's a simple consequence: effect typing. In Haskell you can know what possible effects an operation has from its type. Here's an example from my effect system, Bluefin:

    foo ::
      _ =>
      Exception String e1 ->
      State Int e2 ->
      Eff es Bool
    foo = ...
We know that `foo` produces a `Bool` and the only effects it can do are to throw a `String` exception and mutate an `Int` state. That's it. It can't yield anything to a stream, it can't make network connections, it can't read from disk. In order to compose these operations together, `Eff` has to be an instance of `Monad`. That's the only way `Monad` turns up in this thing at all.

So, that's what you get in Haskell that Python doesn't give you.

replies(1): >>44453057 #
1. bjourne ◴[] No.44453057{5}[source]
Those annotations create a compile-time enforced typological relationship between the input and output values of the function. Python doesn't have mandatory type-checking so it can't do that. But parent wasn't referring to type-checking. They claimed monads have expressive power unavailable in other languages.
replies(1): >>44457808 #
2. tome ◴[] No.44457808[source]
> Those annotations create a compile-time enforced typological relationship between the input and output values of the function. Python doesn't have mandatory type-checking so it can't do that

Python doesn't have (mandatory) compile time type checking, no, but in principle a dynamically typed language could still be referentially transparent, and then it would (or at least could) still be the case that the only effects that a particular operation can perform are those arguments that are passed into it.

> But parent wasn't referring to type-checking. They claimed monads have expressive power unavailable in other languages.

That's true. But think of other syntax sugar like async/await. That comes for free in Haskell with monads and do notation.