我正在设计一个基本上使用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"
Run Code Online (Sandbox Code Playgroud)
最近,我了解了ReaderT设计模式与mtl StateT的关系,该模式鼓励StateT
在ReaderT
over 内使用可变引用进行替换IO
。
我想知道如何使用ReaderT修改代码。最具体地说,许多Lens
职能都有类型:(MonadState s m)
显然需要在国家内部。这是否意味着Lens
库函数是为StateT设计的,而不是为ReaderT设计的?如何Lens
与ReaderT
设计模式一起使用?
从我所见,ReaderT模式用户通常不使用MonadState镜头运算符。相反,使用view
来访问所需的MVar(或您要处理的任何可变变量)并照常进行更新(例如,使用ModifyMVar)。
不过,RIO monad提供了适当的MonadState实例。比我的更好的答案可能是很轻松地使您的代码适应RIO monad。