If we have the following two functions, add and subtract, it is simple to chain them to run a series of calculations on an input:
add :: Int -> State Int ()
add n = state $ \x -> ((),x+n)
subtract :: Int -> State Int ()
subtract n = state $ \x -> ((),x-n)
manyOperations :: State Int ()
manyOperations = do
add 2
subtract 3
add 5
--etc
result = execState manyOperations 5
--result is 9
If we want to print out the state after each calculation is done, we use the StateT
monad transformer:
add :: Int -> StateT Int IO ()
add n = StateT $ \x -> print (x+n) >> return ((),x+n)
subtract :: Int -> StateT Int IO ()
subtract n = StateT $ \x -> print (x-n) >> return ((),x-n)
manyOperations :: StateT Int IO ()
manyOperations = do
add 2
subtract 3
add 5
main = runStateT manyOperations 5
-- prints 7, then 4, then 9
Is it possible to replicate this "combined computation and printing" without StateT
or any custom datatypes?
As far as I know it's possible to do all the processes that MaybeT IO a
can do using IO (Maybe a)
, but it seems like that's because it's just nested monads. On the other hand, StateT
might not have an alternative because s -> (a,s)
is fundamentally different to s -> m (a,s)
I can only see two directions the code could go: using State Int (IO ())
or IO (State Int ())
, but both of these seem nonsensical given the implementation of StateT
I believe it is impossible. Am I correct?
Note: I know this is completely impractical, but I couldn't find any solution after some hours of work, which means I'm correct or my skills aren't enough for the task.