如何解决monad-coroutine 协程的 MonadError 实例,用于任何挂起函子
是否可以为具有任意暂停 MonadError
的 monad-coroutine
Coroutine
编写 Functor
实例。
即
instance (MonadError e m,Functor s) => MonadError (Coroutine s m) where
throwError = lift . throwError
catchError c h = lift $ catchError (_ c) (_ . h)
什么东西可以钻进洞里?他们需要将 Coroutine s m r
转换为 m r
,但我看不出这对于任意 s
是如何可能的。
解决方法
是的,这是可能的。 Coroutine
本质上与 FreeT
相同,后者有一个 MonadError
实例。
请注意,您的开始是错误的;您不能以 lift
开头。问题出现的时间比您想象的要早。
catchError :: Coroutine f m a -> (e -> Coroutine f m a) -> Coroutine f m a
catchError c f = lift _
==>
_ :: m a
即使您不必处理捕捉错误,也无法填补那个漏洞!
lift
确实不能胜任一般提升 catch
类函数的任务。
这种类型检查。不过,我不确定这是否合法。
{-# LANGUAGE FlexibleInstances,MultiParamTypeClasses,UndecidableInstances #-}
import Data.Bifunctor
import Control.Monad.Except
import Control.Monad.Coroutine
instance (MonadError e m,Functor s) => MonadError e (Coroutine s m) where
throwError = lift . throwError
Coroutine c `catchError` h = Coroutine $ fmap (first (fmap (`catchError` h))) c `catchError` (resume . h)
在英语中,其工作原理如下:首先,尝试运行 c
的单个步骤。三种情况是可能的:
- 如果这引发错误,那么我们使用
h
处理错误并返回它所做的任何事情。 - 如果成功并返回最终值,那么我们将返回相同的最终值。
- 如果成功并返回一个暂停,那么我们还没有收到错误,但以后可能还会有,所以我们
fmap (`catchError` h)
在暂停函子上并返回它,递归这样我们有机会抓住以后再说吧。
编辑:我在看到 dfeuer 的回答或知道 FreeT
的实例之前写了这个,但那个实例与这个实例非常相似。这让我觉得这是合法的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。