让我们从你目前所拥有的开始:
getDirection :: State GameState Double
getDirection = do
x <- get
return x
(顺便说一句,这实际上与getDirection = get 相同,因为您只是运行get 并返回其返回值。)
首先,这里的x 是什么类型?您的状态是GameState 类型,而get 只是获取状态,所以x :: GameState。所以我们可以对其进行模式匹配得到:
getDirection :: State GameState Double
getDirection = do
(GameState map dir bool) <- get
return (GameState map dir bool)
此时应该很明显该做什么:只需返回 dir 而不是 (GameState map dir bool)。
当我想改变方向时,我使用 put 还是 modify?
你不应该在同一篇文章中问两个问题,但要回答这个问题,让我们看看它们的类型:
put :: s -> State s ()
modify :: (s -> s) -> State s ()
这个想法是put 只是写入一个新状态,而modify 采用现有状态并使用给定函数修改它。这些功能实际上是等效的,这意味着您可以将其中一个功能替换为另一个:
-- write ‘put’ using ‘modify’
put s = modify (\_oldState -> s)
-- write ‘modify’ using ‘put’ (and ‘get’)
modify f = do
oldState <- get
put $ f oldState
但是,通常在不同的情况下使用put 或modify 会更容易。例如,如果您想编写一个全新的状态而不参考旧状态,请使用put;如果您想采用现有状态并对其进行一些更改,请使用modify。在您的情况下,您只想更改方向,因此使用modify 是最简单的,这样您就可以参考以前的状态来更改状态:
changeDirTo :: Double -> State GameState ()
changeDirTo newDir = modify (\(GameState map _ bool) -> GameState map newDir bool)
-- you can also do it using ‘put’, but it’s a bit harder and less elegant:
changeDirTo2 :: Direction -> State GameState ()
changeDirTo2 newDir = do
(GameState map _ bool) <- get
put $ GameState map newDir bool
另一方面,如果你(比如说)想分配一个全新的GameState,put 会更容易:
putNewGameState :: GameState -> State GameState ()
putNewGameState gs = put gs
-- the above is the same as:
-- putNewGameState = put
-- you can also do it using ‘modify’, but it’s a bit harder and less elegant:
putNewGameState2 :: GameState -> State GameState ()
putNewGameState2 gs = put (\_oldState -> gs)