Haskell 广义共程悬挂式
我正在尝试,并且有一个协同程序,它将从外部请求所有Haskell 广义共程悬挂式,haskell,types,coroutine,Haskell,Types,Coroutine,我正在尝试,并且有一个协同程序,它将从外部请求所有IO操作。因此,我有自己的定制悬架类型IORequest。问题是,对于每种返回类型,我都需要向IORequest添加一个额外的构造函数 下面是一个工作示例(需要和) (不过,我无法使它工作,因为当我们尝试在str中运行它时,a会逃逸。您关于将数据类型更改为包含存在量词的评论似乎完全合理。您的大多数函数不会更改 data IORequest x = forall a . RunIO (IO a) (a -> x) instance Func
IO
操作。因此,我有自己的定制悬架类型IORequest
。问题是,对于每种返回类型,我都需要向IORequest
添加一个额外的构造函数
下面是一个工作示例(需要和)
(不过,我无法使它工作,因为当我们尝试在
str中运行它时,a
会逃逸。您关于将数据类型更改为包含存在量词的评论似乎完全合理。您的大多数函数不会更改
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)
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
您的循环函数也不会真正改变-您只需要不忽略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)
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
现在只是与IO
同构。这遵循左kan扩展定律(即,lantocomposedjaint
和composedjainttolan
是同构的见证),但可以直接写入:
actuallyJustIO_1 :: IORequest a -> IO a
actuallyJustIO_1 = fmap runIdentity . lanToComposedAdjoint
actuallyJustIO_2 :: IO a -> IORequest a
actuallyJustIO_2 = composedAdjointToLan . fmap Identity
这两个函数显然是彼此的左逆和右逆,见证了IORequest
和IO
之间的同构。是否真的有必要将IO放入函子中,而不是将其作为Coroutine f m
的“基单子”?直观地说,这就是它所属的位置。如果我删除IO的外观在IORequest
中,我可以写入requestString m=lift m>=\x->suspend(GetString x return)
使用基本相同的类型,requestString::Monad m=>m String->Coroutine IORequest m String
我对存在类型没有问题。当然,它相当于newtype IORequest x=IORequest{runIORequest::iox}
,不是吗?这只是一个实验。我想把纯代码从IO中分离出来。假设这个协同程序非常庞大,它需要时不时地进行一些IO调用。我不知道它是否会有任何好处,ghc是否能够以当前的形式对这个协同程序进行更好的优化,或者完全在IO中运行的代码会做得更好?我有n好的,我不是反对它,只是提出一些观点。我认为,如果你使用这种类型的东西,最好是在底部使用IO,而不是标识;可以说,你已经为复杂性付出了代价。Coroutine确实有一个MonadIO的例子。但是暂停会有所改变我认为像ReadFile FilePath(Text->x)
这样的程序更符合这个库的精神。
actuallyJustIO_1 :: IORequest a -> IO a
actuallyJustIO_1 = fmap runIdentity . lanToComposedAdjoint
actuallyJustIO_2 :: IO a -> IORequest a
actuallyJustIO_2 = composedAdjointToLan . fmap Identity