泛型协程暂停类型

我正在尝试的事情,并有一个协同程序,它将要求所有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。在此之前,从左边根延伸(即认为lanToComposedAdjointcomposedAdjointToLan看到了一种同构),但可以直接写入法律:

actuallyJustIO_1 :: IORequest a -> IO a 

actuallyJustIO_1 = fmap runIdentity . lanToComposedAdjoint

actuallyJustIO_2 :: IO a -> IORequest a

actuallyJustIO_2 = composedAdjointToLan . fmap Identity

这两个函数明确彼此的左边和右边倒数,见证IORequestIO之间的同构。

以上是 泛型协程暂停类型 的全部内容, 来源链接: utcz.com/qa/266666.html

回到顶部