Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I just do not get what problem they solve.

share|improve this question

closed as too broad by gnat, MichaelT, Bart van Ingen Schenau, Martijn Pieters, amon Feb 19 at 16:20

There are either too many possible answers, or good answers would be too long for this format. Please add details to narrow the answer set or to isolate an issue that can be answered in a few paragraphs.If this question can be reworded to fit the rules in the help center, please edit the question.

1  
Almost a duplicate of: programmers.stackexchange.com/questions/25569/… –  Orbling Jan 22 '11 at 14:09
1  
I think this edit is a bit extreme. I think your question was essentially a good one. It's just that some parts of it were a bit... argumentative. Which is probably just the result of the frustration of trying to learn something you just weren't seeing the point of. –  Jason Baker Jan 22 '11 at 18:31
    
@SnOrfus, I was the one who bastardized the question. I was too lazy to edit it properly. –  Job Aug 3 '11 at 2:20

6 Answers 6

If you're familiar with the GoF patterns, monads are like the Decorator pattern and Builder pattern put together, on steroids, bitten by a radioactive badger.

There are better answers up above, but some of the specific benefits I see are:

  • monads decorate some core type with additional properties without changing the core type. For example, a monad might "lift" String and add values like "isWellFormed", "isProfanity" or "isPalindrome" etc.

  • similarly, monads allow conglomerating a simple type into a collection type

  • monads allow late binding of functions into this higher-order space

  • monads allow mixing arbitrary functions and arguments with an arbitrary data type, in the higher-order space

  • monads allow blending pure, stateless functions with an impure, stateful base, so you can keep track of where the trouble is

A familiar example of a monad in Java is List. It takes some core class, like String, and "lifts" it into the monad space of List, adding information about the list. Then it binds new functions into that space like get(), getFirst(), add(), empty(), etc.

On the large scale, imagine that instead of writing a program, you just wrote a big Builder (as the GoF pattern), and the build() method at the end spat out whatever answer the program was supposed to produce. And that you could add new methods to your ProgramBuilder without recompiling the original code. That's why monads are a powerful design model.

share|improve this answer

Kind of an old question but it's a really good one, so I'll answer.

You can think of monads as blocks of code for which you have complete control over how they're executed: what each line of code should return, whether the execution should stop at any point, whether some other processing should happen between each line.

I'll give some examples of things that monads enable that would be difficult otherwise. None of these examples are in Haskell, just because my Haskell knowledge is a bit shaky, but they're all examples of how Haskell has inspired the use of monads.

Parsers

Normally, if you wanted to write a parser of some sort, say to implement a programming language, you would have to either read the BNF specification and write a whole bunch of loopy code to parse it, or you would have to use a compiler compiler like Flex, Bison, yacc etc.. But with monads, you can make a kind of "compiler parser" right in Haskell.

Parsers can't really be done without either monads or special-purpose languages like yacc, bison etc.

For instance, I took the BNF language specification for the IRC protocol:

message    =  [ ":" prefix SPACE ] command [ params ] crlf
prefix     =  servername / ( nickname [ [ "!" user ] "@" host ] )
command    =  1*letter / 3digit
params     =  *14( SPACE middle ) [ SPACE ":" trailing ]
           =/ 14( SPACE middle ) [ SPACE [ ":" ] trailing ]

nospcrlfcl =  %x01-09 / %x0B-0C / %x0E-1F / %x21-39 / %x3B-FF
                ; any octet except NUL, CR, LF, " " and ":"
middle     =  nospcrlfcl *( ":" / nospcrlfcl )
trailing   =  *( ":" / " " / nospcrlfcl )

SPACE      =  %x20        ; space character
crlf       =  %x0D %x0A   ; "carriage return" "linefeed"

And crunched it down to about 40 lines of code in F# (which is another language that supports monads):

type UserIdentifier = { Name : string; User: string; Host: string }

type Message = { Prefix : UserIdentifier option; Command : string; Params : string list }

let space = character (char 0x20)

let parameters =
    let middle = parser {
        let! c = sat <| fun c -> c <> ':' && c <> (char 0x20)
        let! cs = many <| sat ((<>)(char 0x20))
        return (c::cs)
    }
    let trailing = many item
    let parameter = prefixed space ((prefixed (character ':') trailing) +++ middle)
    many parameter

let command = atLeastOne letter +++ (count 3 digit)

let prefix = parser {
    let! name = many <| sat (fun c -> c <> '!' && c <> '@' && c <> (char 0x20))   //this is more lenient than RFC2812 2.3.1
    let! uh = parser {
        let! user = maybe <| prefixed (character '!') (many <| sat (fun c -> c <> '@' && c <> (char 0x20)))
        let! host = maybe <| prefixed (character '@') (many <| sat ((<>) ' '))
        return (user, host)
    }
    let nullstr = function | Some([]) -> null | Some(s) -> charsString s | _ -> null
    return { Name = charsString name; User = nullstr (fst uh); Host = nullstr (snd uh) }
}

let message = parser {
    let! p = maybe (parser {
        let! _ = character ':'
        let! p = prefix
        let! _ = space
        return p
    })
    let! c = command
    let! ps = parameters
    return { Prefix = p; Command = charsString c; Params = List.map charsString ps }
}

F#'s monad syntax is quite ugly compared to Haskell's, and I could likely have improved this quite a bit -- but the point to take home is that structurally, the parser code is identical to the BNF. Not only would this have taken a lot more work without monads (or a parser generator), it would have had almost no resemblance to the specification, and thus been terrible both to read and to maintain.

Custom multitasking

Normally, multitasking is thought of as being an OS feature -- but with monads, you can write your own scheduler such that after each instruction monad, the program would pass control over to the scheduler, which would then choose another monad to execute.

One guy made a "task" monad to control game loops (again in F#), so that instead of having to write everything as a state machine that acts on each Update() call, he could just write all the instructions as if they were a single function.

In other words, instead of having to do something like:

class Robot
{
   enum State { Walking, Shooting, Stopped }

   State state = State.Stopped;

   public void Update()
   {
      switch(state)
      {
         case State.Stopped:
            Walk();
            state = State.Walking;
            break;
         case State.Walking:
            if (enemyInSight)
            {
               Shoot();
               state = State.Shooting;
            }
            break;
      }
   }
}

You could do something like:

let robotActions = task {
   while (not enemyInSight) do
      Walk()
   while (enemyInSight) do
      Shoot()
}

LINQ to SQL

LINQ to SQL is actually an example of a monad, and similar functionality could easily be implemented in Haskell.

I won't get into the details since I don't remember all that accurately, but Erik Meijer explains it quite well.

share|improve this answer

Monads are neither good nor bad. They just are. They're tools that are used to solve problems like many other constructs of programming languages. One very important application of them is to make life easier for programmers working in a purely functional language. But they are useful in non-functional languages; it's just that that people rarely realize they're using a Monad.

What is a Monad? The best way to think of a Monad is as a design pattern. In the case of I/O, you could probably think of it as being little more than a glorified pipeline where the global state is what is getting passed between the stages.

For instance, let's take the code you're writing:

do
  putStrLn "What is your name?"
  name <- getLine
  putStrLn ("Nice to meet you, " ++ name ++ "!")

There's a lot more going on here than meets the eye. For instance, you'll notice that putStrLn has the following signature: putStrLn :: String -> IO (). Why is this?

Think about it this way: let's pretend (for simplicity's sake) that stdout and stdin are the only files we can read and write to. In an imperative language, this is no problem. But in a functional language, you can't mutate global state. A function is simply something that takes a value (or values) and returns a value (or values). One way around this is to use the global state as the value that's getting passed into and out of each function. So you could translate the first line of code into something like this :

global_state <- (\(stdin, stdout) -> (stdin, stdout ++ "What is your name?")) global_state

...and the compiler would know to print anything that's added to the second element of global_state. Now I don't know about you, but I would hate to program like that. The way this was made easier was to use Monads. In a Monad, you pass a value that represents some kind of state from one action to the next. This is why putStrLn has a return type of IO (): it's returning the new global state.

So why do you care? Well, the advantages of functional programming over imperative program have been debated to death in several places, so I'm not going to answer that question in general (but see this paper if you want to hear the case for functional programming). For this specific case though, it might help if you understood what Haskell is trying to accomplish.

A lot of programmers feel that Haskell tries to prevent them from writing imperative code or using side effects. That isn't quite true. Think about it this way: an imperative language is one that allows side effects by default, but allows you to write functional code if you really want to (and are willing to deal with some of the contortions that would require). Haskell is purely functional by default, but allows you to write imperative code if you really want to (which you do if your program is to be useful). The point isn't to make it difficult to write code that has side effects. It's to make sure you're explicit about having side effects (with the type system enforcing this).

share|improve this answer
6  
That last paragraph is gold. To extract and paraphrase it a bit: "An imperative language is one that allows side effects by default, but allows you to write functional code if you really want to. A functional language is purely functional by default, but allows you to write imperative code if you really want to." –  Frank Shearar Jan 22 '11 at 7:23
    
It's worth noting that the paper you linked to specifically rejects the idea of "immutability as a virtue of functional programming" right at the beginning. –  Mason Wheeler Aug 2 '11 at 22:55
    
@MasonWheeler: I read those paragraphs, not as dismissing the importance of immutability, but rejecting it as a convincing argument for demonstrating functional programming's superiority. In fact, he says the same thing about the elimination of goto (as an argument for structured programming) a little later in the paper, characterizing such arguments as "fruitless." And yet none of us secretly wish for goto's return. It's simply that you can't argue that goto isn't necessary to people who use it extensively. –  Robert Harvey Feb 16 at 16:28

Haskell enforces Referential Transparency: given the same parameters, every function always returns the same result, no matter how many times you call that function.

That means, for example, that on Haskell (and without Monads) you can not implement a random number generator. In C++ or Java you can do that using global variables, storing the intermediate "seed" value of the random generator.

On Haskell the counterpart of global variables are Monads.

share|improve this answer
    
So ... what if you wanted a random number generator? Is not it a function as well? Even if not, how do I get myself a random number generator? –  Job Jan 22 '11 at 15:43
    
@Job You can make a random number generator inside of a monad (its basically a state-tracker), or you can use unsafePerformIO, the devil of Haskell that should never be used (and in fact will probably break your program if you use randomness inside of it!) –  alternative Feb 13 '11 at 21:02

I'll bite!!! Monads by themselves aren't really a raison d'etre for Haskell (early versions of Haskell didn't even have them).

Your question is a bit like saying "C++ when I look at the syntax, I get so bored. But templates are a highly advertised feature of C++ so I looked at an implementation in some other language".

The evolution of a Haskell programmer is a joke, it's not meant to be taken seriously.

A Monad for the purpose of a program in Haskell is an instance of the type class Monad, that is to say, it's a type that happens to support a certain small set of operations. Haskell has special support for types that implement the Monad type class, specifically syntactical support. Practically what this results in is what has been referred to as a "programmable semi-colon". When you combine this functionality with some of Haskell's other features (first-class functions, laziness by default) what you get is the capability to implement certain things as libraries that have traditionally been considered language features. You can for instance, implement an exception mechanism. You can implement support for continuations and coroutines as a library. Haskell, the language has no support for mutable variables: using this combination of features you can implement them, again as a library.

You ask about "Maybe / Identity / Safe Division monads ???". The Maybe monad is an example of how you might implement (very simple, only one exception) exception handling as a library.

You're right, writing messages and reading user input isn't very unique. IO is a lousy example of "monads as a feature".

But to iterate, one "feature" by itself (e.g. Monads) in isolation from the rest of the language doesn't necessarily immediately appear useful (a great new feature of C++0x is rvalue references, doesn't mean you can take them out of the context C++ because it's syntax bores you and necessarily see the utility). A programming language is not something you get by throwing a bunch of features in a bucket.

share|improve this answer

Programmers all write programs, but the similarities end there. I think programmers differ far more than most programmers can imagine. Take any long-standing "battle", like static variable typing vs runtime-only types, scripting vs compiled, C-style vs object-oriented. You will find it impossible to rationally argue that one camp is inferior, because some of them churn out excellent code in some programming system that seems pointless or even downright unusable to me.

I think different people just think differently, and if you are not tempted by syntactic sugar or especially abstractions that only exist for convenience and actually have a significant runtime cost, then by all means stay away from such languages.

I would however recommend that you at least try to familiarise yourself with the concepts that you're giving up. I have nothing against someone who is vehemently pro-pure-C, as long as they actually understand what the big deal is about lambda expressions. I suspect that most will not immediately become a fan, but at least it'll be there at the back of their minds when they find the perfect problem what would have been oh so much easier to solve with lambdas.

And, above all, try to avoid getting annoyed by fanboy speak, especially by people who don't actually know what they're talking about.

share|improve this answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.