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
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
Statemakes sure to preserve the data stored in it.
These special effects are all programmed into each
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
do block will produce a line from
getThirdLine :: IO String getThirdLine = do getLine 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. getLine
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
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
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.
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