Я пытаюсь разобраться и иметь сопрограмму, которая собирается запросить все действия IO
извне. Поэтому у меня есть мой пользовательский тип подвески IORequest
. Проблема в том, что для каждого типа возвращаемого типа мне нужно добавить дополнительный конструктор в IORequest
.Обобщить подвеску Coroutine
Вот рабочий пример (который требует mtl и monad-coroutine)
{-# LANGUAGE DeriveFunctor #-}
module Main where
import Control.Monad.State
import Control.Monad.Coroutine
main :: IO()
main = loop coroutine initialState
initialState :: Int
initialState = 65432
data IORequest x
= RunIO (IO()) (() -> x)
| GetString (IO String) (String -> x)
deriving Functor
request :: Monad m => IO() -> Coroutine IORequest m()
request x = suspend (RunIO x return)
requestString :: Monad m => IO String -> Coroutine IORequest m String
requestString x = suspend (GetString x return)
coroutine :: Coroutine IORequest (State Int) Int
coroutine = do
str <- requestString (readFile "my.txt")
request (print "hello")
return 5
loop :: Coroutine IORequest (State Int) Int -> Int -> IO()
loop routine state =
do let (request, state') = runState (resume routine) state
case request of
Left (GetString cmd q') -> do
str <- cmd
loop (q' str) state'
Left (RunIO cmd q') -> do
cmd
loop (q'()) state'
Right result -> do
print result
Как вы можете видеть, если в какой-то момент мне нужно запустить действие IO Bool
мне нужно будет продлить IORequest
и обеспечить еще один вспомогательный метод для быть в состоянии успешно использовать его (а также расширять совпадение рисунка в loop
).
Вопрос: может ли IORequest
быть обобщенным как-то разрешить общий (IO a) -> a
переход?
Что-то вроде
data IORequest x
= forall a. RunIO (IO a) (a -> x)
(я не смог заставить его работать, хотя, как a
бы избежать, если мы попытаемся запустить его в str <- cmd
, например)
Действительно ли нужно поставить IO в функтор, вместо того, чтобы использовать его как «базовую монаду» из «Coroutine f m»? Интуитивно это то, где он принадлежит. – Michael
Если я удаляю появление IO в 'IORequest', я могу написать' requestString m = lift m >> = \ x -> suspend (GetString x return) 'с по существу тем же типом' requestString :: Monad m => m String -> Coroutine IORequest m String' – Michael
У меня нет проблем с экзистенциальным типом, http://lpaste.net/1570704776058896384. Конечно, это эквивалентно 'newtype IORequest x = IORequest {runIORequest :: IO x}', no? – Michael