如何在 State monad 中包装链式有状态计算?

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

我有这种格式的计算:s -> a -> s,其中 s 是某个状态的类型。这样一个函数的结果也是下一次求值的状态。例如,

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

那么,appendInt "Int: " 1会给出"Int: 1",而(appendInt $ appendInt "Int: 1") 2会给出"Int: 12"。但是,我找不到将这种计算放在 State Monad 中的方法。

一开始猜的是s -> (s,s),但是后来a传不进去,然后又试了(a -> s) -> (s, a -> s),但是还是没法传s as -> (a,s) 不起作用,因为 a 是输入而不是输出。

那么我应该如何包装这个计算呢? State monad 适合这个吗?

当然可以,例如这样:

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

如果您将参数的顺序设置得更 "conventional",它只会是 modify 的组合。

Live On Coliru

你可以使用 State 就好了,或者更好地使用 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