Monads are red herrings, if what you're interested in is getting started with functional programming (or even Haskell specifically). It's an unfortunate flaw in the Haskell literature that makes it seem like you have to grok monads to learn Haskell; you don't.
Monads enable syntactic sugar. If you're getting started with Haskell, you'll notice that when you write code that does I/O, you use a weird imperative-looking syntax ("do notation") that looks different to the normal functional style:
main :: IO ()
main = do
putStrLn "Please enter your name"
name <- getLine
putStrLn ("Hello " ++ name ++ "!")
'putStrLn "Hello"' doesn't actually print anything; it returns an IO value that, when interpreted by the Haskell runtime, prints something: that interpretation takes place when 'main' is run. The do notation is syntactic sugar for creating a sort of compound IO value that interprets as a bunch of actions rather than just one. The reason you can use do notation for IO but not for (all) other Haskell code is that IO values are monadic (which is another and possibly more useful way of saying "IO is a monad"): that just means that they behave in a certain way when combined (to produce that compound value) and obey certain laws to make the do notation well behaved.
Monads are a design pattern to abstract away repetitive functional code. For example, if you write a lot of pure-functional code you sometimes end up having to pass around a 'state' parameter. If a function reads or writes from the state, then any function that calls it has to pass in the state, and so on. This leads to a lot of functions with an extra state parameter, many of which don't even care about the state except to pass it down the call tree. An improvement would be to write a higher-order function which took a function which didn't care about state and wrapped it to produce one that just passed the state through. The State monad encapsulates this wrapping and lets you clean up the rest of your code.
Monads are what's between the lines of an imperative program. Bourne shell scripts have the default error-handling rule that they ignore failing commands unless it's the last one executed, or put another way, they run in a monad that ignores errors:
cat nonexistent.txt # prints an error message
echo Done. # still executes, prints "Done."
# script returns success
But you can tell it to run instead in a monad which stops after the first error:
set -e # change the monad, i.e. the error-handling rule
cat nonexistent.txt # prints an error message
echo Done. # never runs
# script returns failure
Old-school Visual Basic has the opposite default, but you can make it behave like a shell script with "ON ERROR RESUME NEXT". Yes, VB had monads.
Monads are a specific example of higher-kinded polymorphism, which is a very powerful and useful concept that's starting to enter the programming mainstream (examples are template concepts in C++ and LINQ in C# and .NET). Parametric polymorphism (List<String> in Java and C#, etc) means you don't have to write a 'reverse' function that works on lists of strings, and another 'reverse' function for lists of ints, etc; you can just write a generic reverse function that works on lists of any kind, because it doesn't need to know the details of the contained type, just how to iterate over a list. However, if you want to reverse an array, you still have to write a new 'reverse'. If your language supports higher-kinded polymorphism, you can write a generic reverse function that works on any kind of container, because all it needs to know is that the container has some well-behaved method of iteration.
(The LINQ example is a bit more subtle, because C# doesn't support higher-kinded polymorphism, but LINQ is a hard-coded exception to that rule. The cool LINQ syntax works for any type which provides certain operations and behaves in a certain way - which just happen to coincide with the requirements for the type to be monadic.)
Each of your statements seems plausible, even profound in itself.
Then I try to combine them and my head explodes.
You don't need to understand Monads to understand Haskell but they're how you print "Hello world"?? Yeah. Your other example also seem pithy and worthy, and again leave me feeling like the result is utterly opaque. You've shown goodness and power and all but it feels like you're holding the real definition behind your back to make the magic look even more magical-er.
How's-about-ya-spit-it-out. What the heck's a monad?
I feel like I've gotten as far as thinking that a monad's like a little interpreter/pre-interpreter. You pass it something like raw code and it binds more meaning to the variables as well as change the context of execution etc, all before that code gets eventually interpreted. Kind of like how you pass fragments of code to Ruby functions and kind of like how c++ templates are parameterized by type.
Wikipedia says "A monad is a construction that, given an underlying type system, embeds a corresponding type system (called the monadic type system) into it (that is, each monadic type acts as the underlying type). This monadic type system preserves all significant aspects of the underlying type system, while adding features particular to the monad." http://en.wikipedia.org/wiki/Monad_(functional_programming) At least that definition doesn't leave me feeling like someone's said "I can't tell you but they're really great"...
No, actually, i've read dozens of explanations, i went metalinguistic and read discussions about discussions of monads, and this guy is totally correct, the ONE SINGLE most important thing to know about a monad, it would seem, is that you are not required to know what a monad is to use it.
You're right - I didn't explain what a monad is a priori, just some of their properties and reasons they're useful. Thanks for calling me out on that, as I should have made it more explicit.
I didn't mean to "hold the real definition behind my back", just felt that others in this thread had explained the definition better than I could. I also wanted to make the point that the definition is not that important unless you actually want to implement your own monad.
You don't need to understand Monads to understand Haskell but they're how you print "Hello world"??
Yes, there's no contradiction here. The idiomatic and easiest way to write Hello World in Haskell involves some unusual, but fairly intuitive, imperative-looking syntax. That syntax only works because the Haskell IO API is monadic, but you really don't need to know that, nor to understand what a monad is, in order to print Hello World.
LINQ is very similar to Haskell's do-notation, and LINQ providers (LINQ-to-Objects, LINQ-to-SQL etc) are monadic, but you don't need to know what a monad is to write "from u in users where u.age > 21 select u.name". If you want to write your own LINQ provider, though, it's probably worth knowing the monad laws.
Monads are basically a design pattern dealing with special data types. Let's say you're in some situation where there's nondeterminism—each function doesn't return just a value, but several possible values. To use a pseudo-C++-like type system, all of your functions have a signature like
List<B> doSomething(A);
where it returns a list of B's to represent every possible value. You want to chain these together, and the naïve way is
foo = doSomething(x)
bar = []
for someFoo in foo:
bar += doSomethingElse(someFoo);
baz = []
for someBar in bar:
baz += doSomeOtherThing(someBar)
So for every function, you have to repeatedly accumulate the possible values for every possible value so far. If you have higher-order functions, you can encapsulate this in a function like this
def bind(f, list):
results = []
for value in list:
results += f(value)
return results
which means the above example could be rewritten as
which is to say it takes a function from a normal type to a "special" type—in this case a list—and applies it to a "special" type—in this case, every element of a list. In this case, we'd say that List, together with the bind function, is monadic. The Haskell types look more like
bind :: (a -> m b) -> m a -> m b
-- or for our particular example
bind :: (a -> [b]) -> [a] -> [b]
The key here—and it's a simple example, so it's probably hard to see how it extends to the hype given—is that you've got a "special" kind of data and you're taking functions which operate on normal (non-special, in this case, non-list) data and writing functions to use them on special data with little work. The cool thing is that it's a really common pattern, which is why Haskell programmers mention it a lot.
(Note: in Haskell, 'bind' is actually an operator written >>=, and the order of its arguments are reversed, so its type is
>>= :: (Monad m) => m a -> (a -> m b) -> m b
but there are reasons for writing it the way I did.)
Monads enable syntactic sugar. If you're getting started with Haskell, you'll notice that when you write code that does I/O, you use a weird imperative-looking syntax ("do notation") that looks different to the normal functional style:
'putStrLn "Hello"' doesn't actually print anything; it returns an IO value that, when interpreted by the Haskell runtime, prints something: that interpretation takes place when 'main' is run. The do notation is syntactic sugar for creating a sort of compound IO value that interprets as a bunch of actions rather than just one. The reason you can use do notation for IO but not for (all) other Haskell code is that IO values are monadic (which is another and possibly more useful way of saying "IO is a monad"): that just means that they behave in a certain way when combined (to produce that compound value) and obey certain laws to make the do notation well behaved.Monads are a design pattern to abstract away repetitive functional code. For example, if you write a lot of pure-functional code you sometimes end up having to pass around a 'state' parameter. If a function reads or writes from the state, then any function that calls it has to pass in the state, and so on. This leads to a lot of functions with an extra state parameter, many of which don't even care about the state except to pass it down the call tree. An improvement would be to write a higher-order function which took a function which didn't care about state and wrapped it to produce one that just passed the state through. The State monad encapsulates this wrapping and lets you clean up the rest of your code.
Monads are what's between the lines of an imperative program. Bourne shell scripts have the default error-handling rule that they ignore failing commands unless it's the last one executed, or put another way, they run in a monad that ignores errors:
But you can tell it to run instead in a monad which stops after the first error: Old-school Visual Basic has the opposite default, but you can make it behave like a shell script with "ON ERROR RESUME NEXT". Yes, VB had monads.Monads are a specific example of higher-kinded polymorphism, which is a very powerful and useful concept that's starting to enter the programming mainstream (examples are template concepts in C++ and LINQ in C# and .NET). Parametric polymorphism (List<String> in Java and C#, etc) means you don't have to write a 'reverse' function that works on lists of strings, and another 'reverse' function for lists of ints, etc; you can just write a generic reverse function that works on lists of any kind, because it doesn't need to know the details of the contained type, just how to iterate over a list. However, if you want to reverse an array, you still have to write a new 'reverse'. If your language supports higher-kinded polymorphism, you can write a generic reverse function that works on any kind of container, because all it needs to know is that the container has some well-behaved method of iteration.
(The LINQ example is a bit more subtle, because C# doesn't support higher-kinded polymorphism, but LINQ is a hard-coded exception to that rule. The cool LINQ syntax works for any type which provides certain operations and behaves in a certain way - which just happen to coincide with the requirements for the type to be monadic.)