如何在 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
a
。 s -> (a,s)
不起作用,因为 a
是输入而不是输出。
那么我应该如何包装这个计算呢? State
monad 适合这个吗?
当然可以,例如这样:
appendIntM :: MonadState String m => Int -> m ()
appendIntM i = modify $ flip appendInt i
如果您将参数的顺序设置得更 "conventional",它只会是 modify
的组合。
你可以使用 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
我有这种格式的计算: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
a
。 s -> (a,s)
不起作用,因为 a
是输入而不是输出。
那么我应该如何包装这个计算呢? State
monad 适合这个吗?
当然可以,例如这样:
appendIntM :: MonadState String m => Int -> m ()
appendIntM i = modify $ flip appendInt i
如果您将参数的顺序设置得更 "conventional",它只会是 modify
的组合。
你可以使用 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