如何在 IO 中包装 monadic 动作

Mar*_*her 4 monads haskell monad-transformers reader-monad

我试图将ReaderT X IOmonad 视为 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
Run Code Online (Sandbox Code Playgroud)

ioAction例如,按时间间隔调度另一个 IO 操作。Game每次都打开monad 似乎有点麻烦——而且感觉不对。

我试图实现的是:

doStuffInGameMonad :: Game a -> Game ()                                                                                                 
doStuffInGameMonad gameAction = ioAction $ gameAction                                                                                   
Run Code Online (Sandbox Code Playgroud)

我的直觉告诉我,这应该是可能的,因为我的Gamemonad 知道 IO。有没有办法隐式转换/解除Gamemonad?

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

4ca*_*tle 5

您可以使用的一种抽象是包中的MonadUnliftIOunliftio-core。您可以使用withRunInIO.

import Control.Monad.IO.Unlift (MonadUnliftIO(..))

doStuffInGameMonad :: MonadUnliftIO m => m a -> m ()
doStuffInGameMonad gameAction = withRunInIO (\run -> ioAction (run gameAction))
Run Code Online (Sandbox Code Playgroud)

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

doStuffInGameMonad :: Game a -> Game ()
doStuffInGameMonad gameAction = mapReaderT ioAction gameAction
Run Code Online (Sandbox Code Playgroud)