Сопрограмма с StateT и ST и IO
Возникли проблемы с группой монад, которые я пытаюсь объединить.
Я использую монад-сопрограмму, State и линзу (так как у меня глубоко вложенное состояние).
У меня был первоначальный подход, где было рабочее решение. Главное здесь то, что я могу запросить выполнение IO
задачи за пределами сопрограммы.
{-# 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
Теперь, в какой-то момент простого государства стало недостаточно, и я нуждаюсь в ST. Я начал пытаться получить ST
внутри StateT
но по какой-то причине не может придумать, как правильно обращаться IO
вне сопрограммы. Есть ли способ придумать подобное runMyType
когда есть изменение в Coroutine
?
type MyType s = Coroutine IORequest (StateT (MyState s) (ST s))
initialState :: ST s (MyState s)
initialState = do
a <- newSTRef 0
return (MyState a)
Все, что я пытаюсь придумать, приводит к ошибке s
убегая или Couldn't match type ‘s’ with ‘s2’
и так далее... Может быть, поможет какой-то другой порядок укладки монад? Или это вообще возможно?
И еще один вопрос, если у вас есть время: в чем разница между MyType s
и этот:
type MyType = forall s. Coroutine IORequest (StateT (MyState s) (ST s))