8 ms·
You've just proved that the monad tutorials you've read are useless. Monads are emphatically not "a way of encapsulating side-effects in a pure lazy language".
by chowells 14y ago
You've just proved that the monad tutorials you've read are useless. Monads are emphatically not "a way of encapsulating side-effects in a pure lazy language". Haskell's IO type is a way of encapsulating side effects in a pure lazy language. Haskell's IO type happens to form a monad. The fact that it forms a monad is completely irrelevant to what it actually does.
Forming a monad is a very abstract consideration. It has to do with the data type supporting a couple operations with specific properties. It doesn't say a thing about what those operations mean, so long as the required properties hold. It's up to specific monads to insert semantics into those operations.
And so yes, the IO type specifies that its monad operations mean "creating a trivial IO action that gives a specific value when executed" and "feed the result of executing an IO action into a function that returns another action." And that turns out to be a sufficient framework for composing IO actions together, once something else is providing them.
But IO isn't the only monad. There are hundreds of others already defined, and an unlimited number that can be created. What matters is that they can implement a couple functions with the required properties.
So I've said monads are abstract. What's the point then? Well, put simply, a language with the kinds of primitives Haskell has can actually put the abstraction into its libraries. This allows writing code that works at the level of the abstraction, rather than any specific implementation. The monad abstraction turns out to be rich enough to implement all kinds of conditionals, loops and recursion structures, function application patterns, etc.
In fact, work with parser combinator libraries has shown that the monad abstraction is the simplest one that allows you to express any context-sensitive grammar. If you've ever studied automata theory, bells should be ringing about now. The monad abstraction is sufficiently rich to express Turing-complete operations over the kinds of types it applies to.
And that's the real point. The monad interface allows you to specify those kinds of operations generically. Once they've been written, you can apply them to any type that provides the interface (correctly).
The fact that there's an IO type that happens to provide the interface is an accident that's only relevant historically. The benefit is much larger than that.
This kind of comes down to Rich Hickey's "simple vs easy" point. Monads are incredibly simple, but they're not easy for people who aren't used to looking for deep abstractions. One of the insights made in Haskell library design is that category theory contains several ideas that are incredibly simple and powerful as abstractions for software creation. Monad is hardly the only one - it's just the only one getting press.
- marshray 14y agoI know that the IO type and monads live at different levels of abstraction. I am interested in the stuff that you were saying about automata theory. But I'm not as smart or have as much time and energy as that lady from Taiwan who implemented the Perl 6 in Haskell parser combinators. In order for me to use Haskell, I need to be able to get fluent enough with it that I can be productive munging data with it. This means IO, it means a database library, regexes, and manipulating binary data. For example, I tried to do a program that would do some HTTP stuff. The HTTP was in the IO monad, but the database connection was in a different monad. So now I'm looking into monad transformers http://book.realworldhaskell.org/read/monad-transformers.html http://book.realworldhaskell.org/read/monad-transformers.htm... (chapter 18) and my head asplodes. I love Haskell, but it's one of the few things I've found to consistently make me feel stupid.
- chowells 14y agoI'd ask, if you know that IO and monads are different, why your first statement was conflating the purpose of IO with the purpose of the monad interface? If I just totally missed a joke - ok, my mistake. But if you really don't see why it matters that the statement is false, I recommend really thinking about it for a bit. Now, on to the thing about Haskell that the endless proliferation of monad tutorials obscures.. You don't actually need to "understand" monads to use it. You can get by on type signatures and the most basic parts of do notation for a long time. In fact, that's what I did. I spent months working on haskell code, understanding the transformations I was making, but not understanding the abstractions beneath them. The first time I really grasped the purpose of the monad interface was when I decided to learn how to use the parsec library. I was a bit unsure how to combine smaller parsers into more complex ones, but just sort of tried do notation - and it worked. It worked exactly how I expected it to. And that's when I realized you could see the monad interface as "The thing you need to make do notation work like you'd expect." Even if I was still fuzzy on the details. But before that, I was making use of monad transformers. I did a poll in the #haskell IRC channel once. Almost everyone agreed monad transformers are easier to learn about than monads. There's just one simple type signature involved, and it's easy to just fit the pieces together, without a deep understanding of what they mean. They end up doing what you expect, anyway. You really can use haskell productively without understanding the underlying abstractions, so long as you are good at following the types. They're there to help you - they do the job pretty well, if you take a bit of time to learn how to apply them.