在Haskell/Understanding monads/State中有一个代码段:
type GeneratorState = State StdGen
rollDie :: GeneratorState Int
rollDie = do generator <- get
let (value, newGenerator) = randomR (1,6) generator
put newGenerator
return value
关于上面第三行中的符号<-
,有一个解释:
我们将带有<-
的伪随机生成器与get一起取出。 get用状态覆盖monadic值(a
中的m a
),将生成器绑定到状态。 (如果有疑问,请回忆一下get和>>=
的定义。
我不明白:(1)generator
对应于定义State
的第一个类型参数? (2)为什么generator
只是State
的两个参数中的一个,而不是两个?当然,从上下文来看,答案是显而易见的,但我不知道有关<-
的具体规则。
据我所知,在评估evalState rollDie (mkStdGen 600)
时,get
将被State (mkStdGen 0) (mkStdGen 0)
取代,并根据RWH的描述&#34; <-
拉动monad&#34;中的东西,这里的东西不是(mkStdGen 0) (mkStdGen 0)
?
答案 0 :(得分:5)
我不完全确定你的问题的措辞,如果我误解了,请纠正我。
do-notation语法<-
的语法糖与重载的绑定运算符(>>=)
之间存在等价。
do { a <- f ; m } ≡ f >>= \a -> do { m }
所以,如果你想要结果,那就像是:
rollDie' :: GeneratorState Int
rollDie' =
get >>= \generator ->
let (value, newGenerator) = randomR (1,6) generator in
put newGenerator >>= \_ ->
return value
如果你理解State monad是如何工作的,那么在实现中它会在每个绑定的隐式参数中绕过状态(即>>=
)。简化的实现可能如下所示:
newtype State s a = State { runState :: s -> (a,s) }
instance Monad (State s) where
return a = State $ \s -> (a, s)
State act >>= k = State $ \s ->
let (a, s') = act s
in runState (k a) s'
get :: State s s
get = State $ \s -> (s, s)
put :: s -> State s ()
put s = State $ \_ -> ((), s)
因此,当专门用于此特定状态monad时,绑定运算符的类型为:
(>>=) :: State s a -> (a -> State s b) -> State s b
函数get
只是将状态作为参数返回的函数,因此您可以检查它,因此它必须与它所在的monad的s
类型相匹配。
-- +--- State
-- | +- Return value (inner state)
-- | |
get :: State s s