Monads: semantics for subroutines

Monads are fairly simple to understand. Each Monad specifies a different way to execute an imperative-style subroutine.

Monads tell what happens between statements
Monads are sometimes called “executable semicolons” because they control what nice automation happens between each and every line of a subroutine. Getting a new useful effect is usually the main purpose for making a new Monad. A few examples :

  • Whenever a line in one of your Maybe subroutines produces Nothing, the entire subroutine will stop and produce Nothing, which saves you from the Java hell of writing a bunch of x = ...; if (x == null) return null; y = g(x); if (y == null) return null; ... for each and every operation that might produce null.
  • State makes sure to preserve the data stored in it.

These special effects are all programmed into each Monad‘s (>>=) function.

Subroutines produce values
Subroutines will do something useful and, at the end, produce a value that can be used by other subroutines that use the same Monad‘s semantics. A do block will produce whatever its last line happens to produce, so if the last line of your do block produces a line from stdin, your do block will produce a line from stdin.

getThirdLine :: IO String
getThirdLine = do getLine
                  -- Our subroutine will produce whatever the last line produces.
                  -- "getLine" produces the next line from stdin.
                  -- Our subroutine will produce the next line from stdin.

To make certain things easier, return is a subroutine that does nothing but produce the value you give to it.

getLastCharOfThirdLine :: IO Char
getLastCharOfThirdLine = do -- "<-" puts the value produced
                            -- by the subroutine on the right
                            -- into the variable on the left.
                            thirdLine <- getThirdLine
                            -- Our subroutine will produce whatever the last line produces.
                            -- "return" is a subroutine that simply produces its argument.
                            -- Our subroutine will produce "last thirdLine".
                            return (last thirdLine)

In Java or C, you may have seen subroutines that have the return type void, which means they don’t produce anything. In Haskell, the idiom is to produce (), using return () if necessary. You’ll see subroutines that produce () quite a bit, particularly if the sole purpose is to cause a side effect (like writing to a file in IO or overwriting the state in State).

Monads are sometimes bundled with special subroutines. IO has a bunch of nice file-handling subroutines. State lets you get the data it now holds and put a replacement.

Domain-specific languages
Because of their flexibility, Monads are used to create domain-specific languages (DSLs) in Haskell. For instance, the programming language BASIC was implemented as a Monad.

This entry was posted in Haskell monads. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s