Monad
A monad in functional programming is a design pattern that allows for sequential composition of operations while handling side effects in a controlled way. Monads originate from mathematical category theory, where they are a specific type of algebraic structure.
Components of monads:
| Mathematics | Programming |
|---|---|
| An endofunctor T | A type constructor |
| A natural transformation η (unit) | A way to wrap values (return) |
| A natural transformation μ (multiplication) | A way to compose operations (bind) |
A monad consists of two fundamental operations:
return(orunit/pure): Function that wraps a value in the monadbind(often as>>=): Operation that chains monadic computations together
Common examples of monads include:
- Maybe/Option monad: Handles computations that might return no value
- List monad: Represents non-deterministic computations with multiple results
- IO monad: Encapsulate side-effects while maintaining functional purity
- State monad: Allows passing state through a sequence of computations
- Reader monad: Provides access to a shared environment/configuration
- Writer monad: Collects additional output (like logs) during computation
Monads are a core concept in Haskell. Languages like Scala, F# (and JavaScript libraries) have adopted monadic patterns.
Code Example
-- Maybe monad example
-- Function that might fail
halve :: Int -> Maybe Int
halve n | even n = Just (n `div` 2)
| otherwise = Nothing
-- Using bind (>>=) for chained computations
divideBySteps :: Int -> Maybe Int
divideBySteps n = return n >>= halve >>= halve >>= halve
-- The same using do notation
divideByStepsWithDo :: Int -> Maybe Int
divideByStepsWithDo n = do
a <- halve n -- If halve n returns Nothing, entire computation returns Nothing
b <- halve a -- Only runs if previous step succeeded
halve b -- Only runs if previous steps succeeded
main :: IO ()
main = do
print $ divideBySteps 80 -- Just 10
print $ divideBySteps 81 -- Nothing (fails at first step)
print $ divideByStepsWithDo 80 -- Just 10