[ How do I wrap a chained stateful computation in State monad? ]

I have computations in this format: s -> a -> s, where s is the type of some state. The result of such a function is also the state of the next evaluation. For example,

appendInt :: String -> Int -> String
appendInt s i = s ++ (show i)

Then, appendInt "Int: " 1 will give "Int: 1", while (appendInt $ appendInt "Int: 1") 2 will give "Int: 12". However, I cannot find a way to put this kind of computation in a State Monad.

A first guess is s -> (s,s), but then a cannot be passed in. Then, I tried (a -> s) -> (s, a -> s), but again it is impossible to get s without a. s -> (a,s) won't work because a is the input instead of output.

How should I wrap this computation, then? Is the State monad appropriate for this?

Answer 1

You can use State just fine, or even better use Writer:

import Control.Monad.Writer
import Control.Monad.State

appendInt :: Int -> Writer String ()
appendInt i = tell $ show i

appendInt' :: Int -> State String ()
appendInt' i = modify (++ show i)

main = do print . execWriter $ do
            tell "Int: "
            appendInt 1
            appendInt 2
          print . flip execState "Int: " $ do
            appendInt' 1
            appendInt' 2

Answer 2

Sure it is possible, for example like this:

appendIntM :: MonadState String m => Int -> m ()
appendIntM i = modify $ flip appendInt i

Had you made the order of arguments more "conventional", it would just be a composition with modify.

Live On Coliru