Coroutine with StateT and ST and IO

having some trouble with a group of monads I'm trying to combine.

I'm using monad-coroutine, State and lens (as I have deeply nested state).

I had an initial approach where there was a working solution. The main point here is that I can request to execute IO tasks outside of Coroutine.

{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleInstances         #-}
{-# LANGUAGE MultiParamTypeClasses     #-}
{-# LANGUAGE UndecidableInstances      #-}

module Main where

import           Control.Monad.Coroutine      (Coroutine(..), suspend, resume)
import           Control.Monad.State          (State, MonadState, MonadIO)
import           Control.Monad.State          (lift, get, put, liftIO, runState)
import           System.Environment           (getArgs)

type MyType = Coroutine IORequest (State MyState)

instance (MonadState s m) => MonadState s (Coroutine IORequest m) where
    get = lift get
    put = lift . put

io :: MonadIO m => IO a -> m a
io = liftIO

data IORequest x = forall a. RunIO (IO a) (a -> x)

instance Functor IORequest where
    fmap f (RunIO x g) = RunIO x (f . g)

data MyState = MyState { _someInt :: Int }

initialState :: MyState
initialState = MyState 1

request :: Monad m => IO a -> Coroutine IORequest m a
request x = suspend (RunIO x return)

myLogic :: MyType [String]
myLogic = do
    args <- request (io getArgs)
    request (io (print args))
    -- do a lot of useful stuff here
    return args

runMyType :: MyType [String] -> MyState -> IO ()
runMyType logic state = do
    let (req, state') = runState (resume logic) state
    case req of
        Left (RunIO cmd q') -> do
            result <- cmd
            runMyType (q' result) state'
        Right _ -> return ()

main :: IO ()
main = runMyType myLogic initialState

Now, at some point a simple State became not enough and I am in a need of ST. I started to try to get the ST inside StateT but for some reason cannot come up with an idea how to properly handle IO outside of coroutine. Is there any way to come up with similar runMyType when there is a change in the Coroutine ?

type MyType s = Coroutine IORequest (StateT (MyState s) (ST s))

initialState :: ST s (MyState s)
initialState = do
    a <- newSTRef 0
    return (MyState a)

Whatever I try to come up with throws some error about s escaping or Couldn't match type 's' with 's2' and so on... Maybe some other order of monad stacking will help? Or is it at all possible?

And another question if you have some time: what is the difference between the above MyType s and this one:

type MyType = forall s. Coroutine IORequest (StateT (MyState s) (ST s))
链接地址: http://www.djcxy.com/p/53214.html

上一篇: 有没有办法手动打开asyncio事件循环

下一篇: 具有StateT和ST和IO的协程