Haskell ReaderT设计模式与MTL StateT模式

McB*_*den 12 haskell

我正在设计一个基本上使用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的关系,该模式鼓励StateTReaderTover 内使用可变引用进行替换IO

我想知道如何使用ReaderT修改代码。最具体地说,许多Lens职能都有类型:(MonadState s m)显然需要在国家内部。这是否意味着Lens库函数是为StateT设计的,而不是为ReaderT设计的?如何LensReaderT设计模式一起使用?

Dan*_*ton 6

从我所见,ReaderT模式用户通常不使用MonadState镜头运算符。相反,使用view来访问所需的MVar(或您要处理的任何可变变量)并照常进行更新(例如,使用ModifyMVar)。

不过,RIO monad提供了适当的MonadState实例。比我的更好的答案可能是很轻松地使您的代码适应RIO monad。

  • 这是使用rio执行此操作的示例:https://gist.github.com/snoyberg/ce5600bbc102cb0a70611e14ecdbf2ef (4认同)