泛型协程暂停类型
我正在尝试的事情,并有一个协同程序,它将要求所有IO
行动从外面。因此,我有我的自定义暂停类型IORequest
。问题是,对于每种返回类型,我需要为IORequest
添加一个额外的构造函数。泛型协程暂停类型
这里是一个工作示例(需要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
例如)
回答:
你有关更改数据类型评论包含一个存在量词似乎是完全合理的。你的大部分功能都不会改变。
data IORequest x = forall a . RunIO (IO a) (a -> x) instance Functor IORequest where
fmap f (RunIO x g) = RunIO x (f.g)
与RunIO
更换其他构造:
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 (RunIO x return)
而且你的循环功能并没有真正改变任何 - 你只需要不忽视的RunIO
内的值:
loop :: Coroutine IORequest (State Int) Int -> Int -> IO() loop routine state =
do let (request, state') = runState (resume routine) state
case request of
Left (RunIO cmd q') -> do
a <- cmd
loop (q' a) state'
Right result -> do
print result
请注意,您的IORequest
也可以这样定义(如果你有一个相当接近NT GHC):
{-# LANGUAGE PatternSynonyms, ViewPatterns #-} import Data.Functor.Kan.Lan (Lan(..))
import Data.Functor.Identity (Identity(..))
type IORequest = Lan Identity IO
pattern RunIO :: IO a -> (a -> x) -> IORequest x
pattern RunIO x f <- Lan ((.Identity) -> f) x
where RunIO x f = Lan (f.runIdentity) x
那么很明显地看到,IORequest
现在只是同构IO
。在此之前,从左边根延伸(即认为lanToComposedAdjoint
和composedAdjointToLan
看到了一种同构),但可以直接写入法律:
actuallyJustIO_1 :: IORequest a -> IO a actuallyJustIO_1 = fmap runIdentity . lanToComposedAdjoint
actuallyJustIO_2 :: IO a -> IORequest a
actuallyJustIO_2 = composedAdjointToLan . fmap Identity
这两个函数明确彼此的左边和右边倒数,见证IORequest
和IO
之间的同构。
以上是 泛型协程暂停类型 的全部内容, 来源链接: utcz.com/qa/266666.html