我正在尝试用 Haskell 编写一个小游戏,并且需要传递大量的状态。我想尝试用 State monad 隐藏状态
现在我遇到了一个问题:接受状态和参数的函数很容易在状态单子中工作。但也有一些函数只将状态作为参数(并返回修改后的状态,或者可能是其他东西)。
在我的代码的一部分中,我有这一行:
let player = getCurrentPlayer state
我希望它不带状态,而是写
player <- getCurrentPlayerM
目前,它的实现看起来像这样
getCurrentPlayer gameState =
(players gameState) ! (on_turn gameState)
并且通过这样编写它似乎很简单,使其在 State monad 中工作:
getCurrentPlayerM = do state <- get
return (players state ! on_turn state)
但是,这引起了 ghc 的投诉!它说,没有因使用“get”而产生 (MonadState GameState m0) 的实例。我已经重写了一个非常相似的函数,除了它的 State monad 形式不是无效的,所以我有预感,我像这样重写了它:
getCurrentPlayerM _ = do state <- get
return (players state ! on_turn state)
果然,它有效!但是我当然得把它叫做getCurrentPlayerM(),我觉得这样做有点傻。传递参数是我首先要避免的!
另一个惊喜:在 ghci 中查看它的类型我得到
getCurrentPlayerM :: MonadState GameState m => t -> m P.Player
但是如果我尝试在我的代码中显式设置它,我会收到另一个错误:“约束 MonadState GameState m 中的非类型变量参数”并提供允许它的语言扩展。我想这是因为我的 GameState 是一种类型而不是类型类,但为什么它在实践中被接受,但当我试图明确说明它时我更困惑。
所以总结一下:
- 为什么我不能在 State monad 中编写空函数?
- 为什么我不能声明我的解决方法函数实际具有的类型?