State Monad
旧的定义newtype State s a = State { runState :: s -> (a,s) }
instance Monad (State s) where
return x = State $ \s -> (x,s)
(State h) >>= f = State $ \s -> let (a, newState) = h s
(State g) = f a
in g newState
这里旧的定义是指API更改之前的定义,也就是Learn You a Haskell for Great Good!(中文版Haskell趣学指南)这本书中的定义。
- newtype State s a = State { runState :: s -> (a,s) }
State 类型是个 newtype,也就是对现有类型的封装。该类型有两个类型参数:表示状态的类型参数 s 以及表示结果的类型参数 a。
State 类型封装的是一个状态转换函数:\s -> (a,s'),通过 runState 字段可以从 State 类型中取出这个函数。
该函数接收一个状态参数 s,经过计算(转换)之后返回一对值:计算结果 a 以及新的状态 s‘。 - instance Monad (State s) where
State s 类型是 Monad 类型类的一个实例。
对比 Monad 类型类的定义,可知 return 函数的类型签名为:
return :: x -> State s x
大致相当于 x -> s -> (x,s)
而 bind 函数的类型签名为:
(>>=) :: State s a -> (a -> State s b) -> State s b
大致相当于 (s -> (a,s)) -> (a -> s -> (b,s)) -> (s -> (b,s))
- return x = State $ \s -> (x,s)
return 函数将 x 封装进了状态转换函数,该函数把结果值设为 x,状态值 s 则保持不变。 - (State h) >>= f = State $ \s ->
对比函数签名,可知 h 的类型为 s -> (a,s)。
而 f 的类型为 a -> State s b,大致相当于 a -> s -> (b,s)
bind 函数组合两个状态转换函数,最终结果仍然是个状态转换函数。
- let (a, newState) = h s
这里将状态转换函数 h 应用于状态 s 上,得到结果值 a 以及新的状态值 newState。 - (State g) = f a
根据 f 的类型 a -> State s b(大致相当于 a -> s -> (b,s)),可知 g 的类型为 s -> (b,s),这里 g 是第二个状态转换函数。 - in g newState
这里将状态转换函数 g 应用于状态 newState 上,从而得出最终的结果值以及更新的状态值。
newtype StateT s m a = StateT { runStateT :: s -> m (a,s) }
instance (Monad m) => Monad (StateT s m) where
return a = StateT $ \s -> return (a, s)
m >>= k = StateT $ \s -> do
~(a, s') <- runStateT m s
runStateT (k a) s'
instance (Functor m) => Functor (StateT s m) where
fmap f m = StateT $ \s ->
fmap (\ ~(a, s') -> (f a, s')) $ runStateT m s
type State s = StateT s Identity
根据新的定义,State 类型只是 StateT 类型的一个特例。
State Monad 函数
- state f:将函数 f 封装进State Monad。
- runState m X:将函数 f 从State Monad中提取出来,调用 f X,同时返回结果值 a 和状态值 s。
- evalState m X:将函数 f 从State Monad中提取出来,调用 f X,但是仅返回结果值 a。
- execState m X:将函数 f 从State Monad中提取出来,调用 f X,但是仅返回状态值 s。
- return X:结果值 a 设为 X,状态值 s 不变。
- get:结果值 a 设为状态值 s,状态值 s 不变。
- put X:状态值 s 设为 X,结果值 a 设为空。
- modify f:状态值 s 设为 f s,结果值 a 设为空。
- gets f:结果值 a 设为 f s,状态值 s 不变。
Prelude Control.Monad.State> runState (return 15) 1
(15,1)
Prelude Control.Monad.State> runState get 1
(1,1)
Prelude Control.Monad.State> runState (put 3) 1
((),3)
Prelude Control.Monad.State> runState (modify (+1)) 1
((),2)
Prelude Control.Monad.State> runState (gets (+1)) 1
(2,1)
Prelude Control.Monad.State> evalState (gets (+1)) 1
2
Prelude Control.Monad.State> execState (gets (+1)) 1
1
Prelude Control.Monad.State> runState (do put 3; return 15) 1
(15,3)
Prelude Control.Monad.State> runState (put 3 >> return 15) 1
(15,3)
随机数
Prelude Control.Monad.State System.Random> let r = state $ randomR (1, 10)
Prelude Control.Monad.State System.Random> do {gen <- newStdGen; return $ evalState r gen}
4
Prelude Control.Monad.State System.Random> newStdGen >>= \gen -> return $ evalState r gen
3
阶乘
fact_state :: State Int Int
fact_state = get >>= \x -> if x <= 1
then return 1
else (put (x - 1) >> fmap (*x) fact_state)
factorial :: Int -> Int
factorial = evalState fact_state
Prelude Control.Monad.State.Strict Control.Applicative> factorial <$> [1..10]
[1,2,6,24,120,720,5040,40320,362880,3628800]
斐波那契数列
fibs_state :: State (Int, Int, Int) Int
fibs_state = get >>= \(x1, x2, n) -> if n == 0
then return x1
else (put (x2, x1+x2, n-1) >> fibs_state)
fibonacci n = evalState fibs_state (0, 1, n)
Prelude Control.Monad.State.Strict Control.Applicative> fibonacci <$> [1..10]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
参考链接
Confusion over the State Monad code on “Learn you a Haskell”
The State Monad: A Tutorial for the Confused?
Three Useful Monads
Where is the data constructor for 'State'?
Implementing factorial and fibonacci using State monad (as a learning exercise)