在真实世界的哈斯克尔chapter中,他们为(>>)
提供了这样的理由:
当我们想要按特定顺序执行操作时,我们使用此功能,但不关心其结果是什么。
然后他们给出了一个很好的例子来证明它:
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
答案 0 :(得分:9)
因为put
有副作用。它将某些东西粘贴到状态monad中,以后可以访问和修改。
它的返回值只是()
,这很无聊,所以我们不关心它,但我们当然希望确保将新的随机生成器置于状态。
想到这样,状态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)
此处x
为1
,y
为2
。显而易见,除了它的回报价值之外,还有其他有趣的效果。