Common Monads: Reader, Writer, State
These come from the mtl/transformers packages. State s a is a newtype around s -> (a, s). Reader is a function r -> a. Writer pairs a result with a Monoid.
import Control.Monad.Reader
import Control.Monad.Writer
import Control.Monad.State
-- Reader: read-only shared environment (configuration, dependencies)
data Config = Config {verbose :: Bool, appName :: String}
logMsg :: String -> Reader Config String
logMsg msg = do
cfg <- ask
name <- asks appName
pure (if verbose cfg then "[" ++ name ++ "] " ++ msg else msg)
-- runReader (logMsg "started") (Config True "demo") == "[demo] started"
-- local (\c -> c {verbose = False}) action -- run with a modified environment
-- Writer: accumulate output (logs, metrics) alongside a result
collatz :: Int -> Writer [Int] Int
collatz 1 = tell [1] >> pure 0
collatz n = do
tell [n]
steps <- collatz (if even n then n `div` 2 else 3 * n + 1)
pure (steps + 1)
-- runWriter (collatz 6) == (8,[6,3,10,5,16,8,4,2,1])
-- (Writer is lazy and can leak memory; for logging in real apps prefer a logging library or StateT)
-- State: threading state through computations
type Stack = [Int]
push :: Int -> State Stack ()
push x = modify (x :)
pop :: State Stack (Maybe Int)
pop = do
s <- get
case s of
[] -> pure Nothing
(x : xs) -> put xs >> pure (Just x)
stackOps :: State Stack (Maybe Int)
…