【问题标题】:Haskell ReaderT Design Pattern vs mtl StateT patternHaskell ReaderT 设计模式与 mtl StateT 模式
【发布时间】: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 设计的?如何使用LensReaderT 设计模式?

【问题讨论】:

  • ReaderT 不会让你更新状态
  • 如果您的ReaderT 超过IO,您可以在您的环境中保留一个可变引用并使用它来存储状态。对于使用此技巧的库示例,当SomeRef 在环境hackage.haskell.org/package/rio-0.1.8.0/docs/RIO.html#t:RIO 中时,RIO 有一个MonadState 实例@

标签: haskell


【解决方案1】:

据我所知,ReaderT 模式用户通常不使用 MonadState 镜头运算符。相反,使用view 访问所需的 MVar(或您正在处理的任何类型的可变 var)并照常更新它(例如使用 modifyMVar)。

不过,RIO monad 提供了一个合适的 MonadState 实例。比我更好的答案可能会很容易地使您的代码适应 RIO monad。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
  • 2017-08-01
  • 2015-06-29
  • 1970-01-01
相关资源
最近更新 更多