我试图将 ReaderT X IO
monad 视为 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。有没有办法隐式转换/取消 Game
monad?
如果我的术语不正确,请原谅。
最佳答案
您可以使用的一个抽象是 MonadUnliftIO
来自 unliftio-core
的类(class)包裹。您可以使用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
关于haskell - 如何在 IO 中包装单子(monad) Action ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56747974/