使用State Monad时理解符号"< - "?

abe*_*008 2 monads haskell state-monad

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
Run Code Online (Sandbox Code Playgroud)

关于<-上面第三行中的符号,有一个解释:

我们<-与get一起取出伪随机生成器.获得覆盖一元值(am a)与状态,结合发电机的状态.(如果有疑问,请回忆一下get和>>=above 的定义).

我不明白:(1)generator对应于定义的第一个类型参数State?(2)为什么generator只是两个参数中的一个State,而不是两个?当然,从上下文来看,答案是显而易见的,但我不知道具体的规则<-.

据我所知,在评估时evalState rollDie (mkStdGen 600),get将被替换为State (mkStdGen 0) (mkStdGen 0),并且,根据RWH的描述" <-拉出monad的东西",这里的东西不是(mkStdGen 0) (mkStdGen 0)

Ste*_*ehl 5

我不完全确定你的问题的措辞,所以如果我误解了,请纠正我.

do-notation语法的语法糖<-与重载的bind运算符之间存在等价(>>=).

do { a <- f ; m } ? f >>= \a -> do { m }
Run Code Online (Sandbox Code Playgroud)

因此,如果你要去除绑定,它看起来像:

rollDie' :: GeneratorState Int
rollDie' =
  get >>= \generator ->
    let (value, newGenerator) = randomR (1,6) generator in
    put newGenerator >>= \_ ->
      return value
Run Code Online (Sandbox Code Playgroud)

如果你理解State monad是如何工作的,那么在实现中它会在每个bind(即>>=)的隐式参数中绕过状态.简化的实现可能如下所示:

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)
Run Code Online (Sandbox Code Playgroud)

因此,当专门用于此特定状态monad时,绑定运算符具有以下类型:

(>>=) :: State s a -> (a -> State s b) -> State s b
Run Code Online (Sandbox Code Playgroud)

该函数 get只是将状态作为参数返回的函数,因此您可以检查它,因此它必须匹配s它所在的monad 的类型.

--           +--- State
--           | +- Return value (inner state)
--           | |
get :: State s s
Run Code Online (Sandbox Code Playgroud)