Я разрабатываю небольшую игру, в которой в основном используется 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 vs mtl StateT, который поощряет замену StateT
изменяемой ссылкой внутри ReaderT
поверх IO
.
Интересно, как мне адаптировать код с помощью ReaderT. В частности, многие функции Lens
имеют типы: (MonadState sm)
которые, очевидно, должны находиться внутри State. Означает ли это, что функции библиотеки Lens
предназначены для StateT, а не для ReaderT? Как использовать Lens
с ReaderT
?