您的位置:首页 > 其它

Haskell语言学习笔记(9)State Monad

2017-02-08 14:57 701 查看

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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: