4

在 Real World Haskell章节中,他们给出了这样的理由(>>)

当我们想按特定顺序执行操作时,我们会使用此功能,但不关心一个操作的结果是什么。

然后他们举了一个很好的例子来证明它:

ghci > print "foo" >> print "bar"
"foo"
"bar"

在本章的后面,他们使用相同的概念在 State monad 中生成随机值:

getRandom :: Random a => RandomState a
getRandom =
  get >>= \gen ->
  let (val, gen') = random gen in
  put gen' >>
  return val

put gen' >>但是为什么在这种情况下他们最终会忽略它的输出值时使用该语句。为什么上面的函数不能是这样的:

getRandom :: Random a => RandomState a
getRandom =
  get >>= \gen ->
  let (val, gen') = random gen in
  return val

只是为了完成这个问题,我为上述上下文添加了相关的类型定义和函数:

newtype State s a = State {
  runState :: s -> (a, s)
  }

get :: State s s
get = State $ \s -> (s, s)

put :: s -> State s ()
put s = State $ \_ -> ((), s)

type RandomState a = State StdGen a
4

1 回答 1

9

因为put有副作用。它将一些东西粘贴到状态 monad 中,以后可以访问和修改。

它的返回值只是()无聊,所以我们不关心它,但我们当然要确保我们将新的随机生成器放入状态。

这样想,state monad 真的是一个函数s -> (a, s)。并且put

put s = \oldState -> (() , s)

所以这有一个副作用,就是丢弃旧状态并替换它。考虑这个例子

  test = put 1 >> get >>= \x -> put 2 >> get >>= \y -> return (x, y)

  -- or with do notation
  test' = do
    put 1
    x <- get
    put 2
    y <- get
    return (x, y)

x1y2。显然 put 不仅具有返回值,还具有有趣的效果。

于 2013-11-30T17:16:30.497 回答