Monad-coroutine 的 MonadError 实例 Coroutine for any suspension Functor

MonadError instance for monad-coroutine Coroutine for any suspension Functor

是否可以为 monad-coroutine Coroutine 写一个 MonadError 实例并任意挂起 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.

怎么可能

是的,这是可能的。 CoroutineFreeT本质上是一样的,后者有一个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 和 return 处理错误。
  • 如果成功并且 return 是最终值,那么我们 return 相同的最终值。
  • 如果成功并且 return 暂停,那么我们还没有收到错误,但稍后可能会出现错误,因此我们 fmap (`catchError` h) 暂停函子 return , 递归以便我们以后有机会抓住它。

编辑:我在看到 dfeuer 的回答或知道 FreeT 的实例之前写了这篇文章,但那个实例与这个实例非常相似。这让我觉得这个是合法的。