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