我正在设计一个基本上使用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
的{{1}}内部用可变引用替换ReaderT
。
我想知道如何使用ReaderT修改代码。最具体地说,许多IO
函数的类型为:Lens
,显然需要在一个国家内部。这是否意味着(MonadState s m)
库函数是为StateT设计的,而不是为ReaderT设计的?如何将Lens
与Lens
设计模式一起使用?