【发布时间】:2019-03-11 21:25:35
【问题描述】:
我正在设计一个基本上使用 StateT 并且只是更新状态的小游戏。以下是简化版:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.State
import Control.Monad.State.Class
import System.Random
data PlayerState = PlayerState {
_psName :: String,
_psScore :: Int
} deriving (Show)
makeClassy ''PlayerState
data Game = Game {
_turns :: Int,
_players :: [PlayerState]
} deriving (Show)
makeClassy ''Game
randomGameInit :: IO Game
randomGameInit = do
players <- replicateM 5 $ PlayerState <$> (replicateM 4 $ randomRIO ('a', 'z')) <*> randomRIO (1,10)
return $ Game 0 players
update :: (MonadState s m, HasGame s) => m ()
update = do
players . ix 0 . psName %= (\_ -> "mordor")
turns %= (+1)
exitCondition <- fmap (>10) (turns <%= id)
unless exitCondition update
main :: IO ()
main = do
init <- randomGameInit
runStateT update init >> print "Game Over"
我最近了解了ReaderT Design Pattern vs mtl StateT,它鼓励将StateT 替换为ReaderT 中的可变引用而不是IO。
我想知道如何使用 ReaderT 调整代码。最具体地说,许多Lens 函数具有类型:(MonadState s m),显然需要在状态内。这是否意味着 Lens 库函数是为 StateT 而不是为 ReaderT 设计的?如何使用Lens 和ReaderT 设计模式?
【问题讨论】:
-
ReaderT不会让你更新状态 -
如果您的
ReaderT超过IO,您可以在您的环境中保留一个可变引用并使用它来存储状态。对于使用此技巧的库示例,当SomeRef在环境hackage.haskell.org/package/rio-0.1.8.0/docs/RIO.html#t:RIO 中时,RIO有一个MonadState实例@
标签: haskell