haskell - 如何在 IO 中包装单子(monad) Action

标签 haskell monads monad-transformers reader-monad

我试图将 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/

相关文章:

haskell - Haskell 中的旋转函数

haskell - monads current "state of the art"是用纯语言做 IO 吗?

haskell - 为什么有一个用于 exceptT 的 MonadMask 实例?

f# - 将面向铁路的故障跟踪转换为 Rx 友好错误

haskell - 由于使用 'minBound' 无法推断(有界 a1)

opengl - Haskell 图形程序关闭过早

linux - Haskell可以用来写shell脚本吗?

haskell - Data.Stream 的 Monad 实例的定义

haskell - 使用来自 REPL 的 Monadic eDSL

haskell - 用状态单子(monad)重构不纯递归?