【发布时间】:2015-03-26 12:45:21
【问题描述】:
为了测试我在 Haskell 中的技能,我决定实现您在 Land of Lisp / Realm of Racket 中找到的第一款游戏。 “猜我的号码”游戏。游戏依赖于可变状态来运行,因为它必须不断更新程序的上限和下限,以了解用户正在考虑的值。
有点像这样:
> (guess)
50
> (smaller)
25
> (bigger)
37
现在,这种事情(据我所知)在 Haskell 中并不完全可能,从 REPL 中调用一些修改全局可变状态的函数,然后立即打印结果,因为它违反了不变性原则。因此,所有交互都必须存在于 IO 和/或 State monad 中。这就是我卡住的地方。
我似乎无法将IO monad 和State monad 组合在一起,所以我可以在同一个函数中获取输入、打印结果和修改状态。
这是我目前得到的:
type Bound = (Int, Int) -- left is the lower bound, right is the upper
initial :: Bound
initial = (1, 100)
guess :: Bound -> Int
guess (l, u) = (l + u) `div` 2
smaller :: State Bound ()
smaller = do
bd@(l, _) <- get
let newUpper = max l $ pred $ guess bd
put $ (l, newUpper)
bigger :: State Bound ()
bigger = do
bd@(_, u) <- get
let newLower = min u $ succ $ guess bd
put $ (newLower, u)
我现在需要做的就是想出一种方法来
- 打印初始猜测
- 接收需要更小/更大数字的命令
- 相应地修改状态
- 递归调用函数,让它再次猜测
我如何以一种优雅的方式结合IO 和State 来实现这一点?
注意:我知道这可能完全不用状态就可以实现;但我想让它保持原汁原味
【问题讨论】:
-
等等,猜数字的是电脑?
-
@Jefffrey 是的,在 Lisp 版本中,计算机猜测,而不是人;这就是为什么实施起来更有趣
标签: haskell state-monad io-monad