如何在IO中包裹单调动作



我试图将ReaderT X IO单子视为IO以实现以下内容:

-- this is the monad I defined:
type Game = ReaderT State IO                                                                                                            
runGame :: State -> Game a -> IO a                                                                                                      
runGame state a = runReaderT a state                                                                                                    
readState :: Game State                                                                                                                 
readState = ask                                                                                                                         
-- some IO action, i.e. scheduling, looping, etc.                                                                                                                    
ioAction :: IO a -> IO ()
ioAction = undefined
-- this works as expected, but is rather ugly                                                                                                                                       
doStuffInGameMonad :: Game a -> Game ()                                                                                                 
doStuffInGameMonad gameAction = do                                                                                                      
  state <- readState                                                                                                               
  liftIO $ ioAction $ runGame state gameAction
例如,

ioAction正在以间隔计划另一个IO操作。每次拆开Game Monad似乎有些麻烦 - 觉得错误。

我要实现的目标是:

doStuffInGameMonad :: Game a -> Game ()                                                                                                 
doStuffInGameMonad gameAction = ioAction $ gameAction                                                                                   

我的直觉告诉我,这应该以某种方式有可能,因为我的Game Monad知道IO。有没有办法隐式转换/Unlift Game Monad?

如果我的术语不正确,请原谅。

您可以使用的一个抽象是unliftio-core软件包中的MonadUnliftIO类。您可以使用withRunInIO

import Control.Monad.IO.Unlift (MonadUnliftIO(..))
doStuffInGameMonad :: MonadUnliftIO m => m a -> m ()
doStuffInGameMonad gameAction = withRunInIO (run -> ioAction (run gameAction))

另一个较少的多态性解决方案是使用mapReaderT

doStuffInGameMonad :: Game a -> Game ()
doStuffInGameMonad gameAction = mapReaderT ioAction gameAction

诀窍是将游戏动作定义为类型类:

class Monad m => GameMonad m where
  spawnCreature :: Position -> m Creature
  moveCreature :: Creature -> Direction -> m ()

然后,使用readert/io操作声明ReaderT State IOGameMonad实例 - 实现spawnCreaturemoveCreature;是的,这可能意味着liftIO的s,但仅在上述实例中 - 您的其余代码将能够无意义地调用spawnCreaturemoveCreature,加上您的功能类型签名将指示该函数具有哪些功能:

spawnTenCreatures :: GameMonad m => m ()

在这里,签名告诉您此功能执行GameMonAd操作 - 例如,它不连接到Internet,写入数据库或启动导弹:(

(实际上,如果您想了解有关此样式的更多信息,那么Google的技术术语是"功能"(

相关内容

  • 没有找到相关文章

最新更新