I 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.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.
I'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.
> 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?
Just for brevity. Everyone knew what I was talking about. I'm sorry. I don't like that I was imprecise and confounded monads with the IO type any more than you do.
Considering that monads in Haskell were discovered as a solution to the unweildy problem of performing I/O in a pure functional language, and that all of the early tutorials approach them from that direction, don't you think it's a teeny bit disingenuous to suddenly act like they are completely unrelated and orthogonal concepts?
Maybe I should take another crack at Haskell. But I'd just started Erlang and Riak...
It's true that the abstraction got attention when they realized it solved the IO problem. (Before the IO type, IO in Haskell was painful.) It's quite possible it wouldn't have become a significant part of the ecosystem without the fact that it solved the IO problem neatly.
But solving the IO problem neatly is a consequence of the value of the abstraction. It solves it so well because of its useful properties.
I'd say you should take another crack at haskell sometime. But if you're learning Erlang now, stick with that for the time being. It's also got plenty to teach.
Monads were originally introduced by Wadler in his Monads for functional programming paper. In it he mentions state and I/O but also exception handling, parsing and non determinism.
Of course you're correct in the literal sense. But reading things like "The History of Haskell: Being Lazy with Class" Hudak, Hughes, Peyton-Jones, Wadler gave me a different perception.
The first time the term monad is mentioned, it is in the description of the agenda of the paper: "monads and input/output (Section 7)".
The second time is "May 1996. ... Monadic I/O made its first appearance, including “do” syntax (Section 7), and the I/O semantics in the Appendix was
dropped."
A few more occurrences of the term and we get to section 3.2 "Haskell is pure" which says "Necessity being the mother
of invention, this embarrassment ultimately led to the invention of
monadic I/O, which we now regard as one of Haskell’s main contributions to the world, as we discuss in more detail in Section 7."
"Section 3.8 Haskell and Miranda ... More fundamentally, Haskell did not adopt Miranda’s abstract data types, using the module system instead (Section 5.3); added monadic I/O (Section 7.2); and incorporated many
innovations to the core Hindley-Milner type system, especially type
classes (Section 6)."
"Section 6.4 Higher-kinded polymorphism
The first major, unanticipated development in the type-class story
came when Mark Jones, then at Yale, suggested parameterising a
class over a type constructor instead of over a type, an idea he
called constructor classes (Jones, 1993). The most immediate and
persuasive application of this idea was to monads ... Jones’s paper appeared in 1993, the same year that monads became
popular for I/O (Section 7). The fact that type classes so directly
supported monads made monads far more accessible and popular; and dually, the usefulness of monadic I/O ensured the adoption
of higher-kinded polymorphism"
The entire Section 7 is called "Monads and input/output"
Section 7.3 "Monadic I/O
Although Wadler’s development of Moggi’s ideas was not directed
towards the question of input/output, he and others at Glasgow soon
realised that monads provided an ideal framework for I/O"
As a Haskell novice I think I could be forgiven for having the perception that the evolution of monads in Haskell was driven by the unwieldyness of managing mutable state (such as I/O) in a pure lazy language.
Yea, I'm not blaming anybody. Just pointing out that it was recognized that monads were useful beyond I/O in the early days. It's definitely true that I/O was a major impetus for them.
I'm going to give a mini monad tutorial here. Hopefully that will also clear up at least some of the confusion in the other threads here.
A monad is a container type with at least these three operations:
1. unit(x): Create a container with a single element x inside.
2. map(f,c): Given a container c with elements, call the function f on each element, and create a new container out of the results.
3. flatten(c): Given a container of containers, we can flatten it down by putting all the elements in the nested containers in a single container.
For example, a List<T> is a monad:
1. unit(x) creates a list with a single element.
2. map(f,list) calls f on each element of the list, and creates a new list out of the results.
3. flatten(listoflists) flattens the nested lists down. Note that flatten only flattens away one level, so if you have a list of lists of lists, then flattening it will get you a list of lists.
These operations have to have some laws, like:
1. map(f, unit(x)) = unit (f x): if we map a function over a container with a single element, we just call the function on that single element and put it inside its own container.
2. flatten(unit(c)) = c: if we wrap a container c in its own single element container unit(c) then flattening it gives us back the original.
3. flatten(map(unit,c)) = c: if we take each element of a container and wrap each one in its own container, and then flatten the result, we get back the original.
Turns out that you can also define these operations for sets and multisets. The interesting thing is that there are more things that fit in the API above. Futures, parsers, probability distributions, I/O operations, mutable state, dynamic scoping, exceptions, optional values, logic programming, continuations, asynchronous programming, and more. Monads are what all those things have in common. I think the only way, ultimately, to learn how monads work is to study many examples. You may ask yourself, for example, what does it mean to flatten a parser? Turns out you can give a meaningful definition for flattening a parser. If you study many such examples, you start to get the pattern.
What makes monads so neat to use is that you can define special syntax for it. For example list comprehensions can be translated to the operations above, which means that list comprehensions also work on all the other things that are monads. So you get "parser comprehensions" and "futures comprehensions". Similarly, mutable state has special concise syntax in imperative languages, but with monads that syntax also works for lists, probability distributions, etc. That's what do-notation is in Haskell.
I hope this helps somebody get interested in what monads really are about.
That said, to use I/O in Haskell you do not need to understand any of this. If you can read this:
do print "What's your name?"
name <- readLn
print ("Hello, " ++ name)
Then you're good to go. You do not need to know that there is a I/O monad underneath this, you can just do like you're coding in an imperative language. The only difference is that the syntax above is not restricted to I/O and mutable state like it is in most languages, but it can also be used for creating parsers, manipulating lists, etc.
For example, the assignment operator in the I/O monad means assignment, but in the list monad it means "take each element of":
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.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.