A monad transformer...
The resulting monad has both:
StateT s mNotes
type MyMonad = StateT String IO
algorithm :: MyMonad Int
algorithm = do
oldState <- get
input <- lift getLine
put input
pure (length oldState)runStateT :: StateT s m a -> s -> m (a, s)Every monad transformer FooT has a runFooT function. For example for StateT:
In our example, we can use that to run the algorithm in the `main` function:
main :: IO ()
main = do
initialState <- getLine
(result, newState) <- runStateT algorithm initialState
print resulttype MyMonad = StateT String (ReaderT Config IO)We can repeat the process of applying a monad transformer to combine more than two effects:
| StateT String |
| ReaderT Config |
| IO |
algorithm :: MyMonad Int
algorithm = do
input <- lift (lift getLine)
...The Stack:
class MonadReader r m where
ask :: m rThe functionality of the different effects is actually defined in typeclasses, for example:
instance MonadReader r m => MonadReader r (StateT s m) where
ask = lift askTransformers typically implement these typeclasses if the base monad implements it:
type MyMonad = StateT String (ReaderT Config IO)
algorithm :: MyMonad Int
algorithm = do
cfg <- ask
...So in practice:
How and why do transformers work?
Live coding