A monad in programming is a composable computation description. Monads are an important construct in functional programming languages like Haskell.
A monad in programming is a composable computation description. Monads are an important construct in functional languages like Haskell.
In Haskell, a Monad is simply any type constructor m
with two functions,
return :: a → m a -- construct `m a` value from an `a` value,
-- and
(>>=) :: m a → (a → m b) → m b -- "bind": combine `m a` value and
-- `a → m b` value into an `m b` value
following several algebraic laws. (::
means "has type".)
A value of type m a
represents (describes) an m
-type computation, producing an a
-type result.
Having defined
(>=>) :: Monad m => (a → m b) → (b → m c) → a → m c
-- f g x
(f >=> g) x = f x >>= g -- a.k.a. "Kleisli composition"
the Monad laws are:
return >=> g = g -- left identity
f >=> return = f -- right identity
f >=> (g >=> h) = (f >=> g) >=> h -- associativity
These types of values can be used to represent a wide variety of different tasks including: I/O, continuations, coroutines, non-determinism, error-handling, mutable state, parsing and more (each with its specific choice for m
). In addition, they are particularly useful for embedding simple DSLs within a functional language like Haskell. In fact, it can be said that Monads are EDSLs, in a certain sense.
More precisely,
mappable computation descriptions are Functors, having
fmap :: (a → b) → m a → m b
operation, as if allowing us to writefmap f c = do { x <- c; return (f x) }
composable mappable computation descriptions are Applicative Functors, having
(<*>) :: m (a → b) → m a → m b
operation, conceptually allowing forc1 <*> c2 = do { x <- c1; y <- c2; return (x y) }
whereas whenever we have composable mappable computation description constructors, i.e. things of type
a → m b
composable with the Kleisli composition operator>=>
, so we can writec >>= g = do { x <- c; y <- g x; return y }
,then we have a Monad.
To quote the user:leftaroundabout from here:
... [an] often-quoted analogy is that an action [i.e. a monadic value of type
IO a
] is like a recipe for a cake, the result [of typea
] is the cake itself.Applying [a function] directly to the IO action would be like taking a knife to cut the recipe in pieces, and expecting that you can then use that recipe to bake a ready-cut cake.
Clearly that's not how it works. You first need to execute (bind) an IO action before you can manipulate the result.
Alternatively, you can use the
fmap
operator. What this does is basically, it takes a recipe and some instruction what to do with the result, and then adds that instruction to the end of the recipe. If you then execute that recipe, the result of it will indeed be a cake cut into pieces.