Haskell 使用管道(-core)的错误处理方法是什么?

Haskell 使用管道(-core)的错误处理方法是什么?,haskell,error-handling,Haskell,Error Handling,我目前正在为我的一个小项目编写一些管道核心/管道。我希望每个解析器提供一个管道,它等待ByteString输入到解析器,并生成任何解析值(重新启动解析器)。如果不进行错误处理,它将具有如下类型 parserP :: Monad m => Parser a -> Pipe ByteString a m r 现在,我不确定如何处理解析错误。我目前的想法是: 将错误添加到返回类型中(即,在中返回值,而不仅仅是r) 要求monad提供错误处理机制(即要求接管管道的monad实现Monad

我目前正在为我的一个小项目编写一些管道核心/管道。我希望每个解析器提供一个管道,它等待
ByteString
输入到解析器,并生成任何解析值(重新启动解析器)。如果不进行错误处理,它将具有如下类型

parserP :: Monad m => Parser a -> Pipe ByteString a m r
现在,我不确定如何处理解析错误。我目前的想法是:

  • 将错误添加到返回类型中(即,在
    中返回值,而不仅仅是
    r
  • 要求monad提供错误处理机制(即要求接管管道的monad实现
    MonadError
  • 通过接管任何monad
    m
    的管道,强制monad提供错误机制
  • 添加参数,让用户指定行为(类似于
    (ParseError->P.Pipe ByteString a m r)
    ,并在出现解析错误时简单地绑定到这样提供的管道)
第一种解决方案似乎是错误的,因为使用管道的返回类型进行错误处理似乎是一种黑客行为。首先,它使与管道的组合更加丑陋,似乎或多或少被最终解决方案所包含(除了可能失去让下游管道能够通过使用tryAwait和stop Waiting值从错误中恢复的能力之外?)

第二个解决方案似乎是错误的,尽管我不太明白为什么。可能是因为它(可能?)还需要使用一个参数将ParseError转换为monad具有的任何错误类型(除非我们希望要求monad实现
MonadError ParseError
,这似乎会导致大量簿记)。最后,我似乎不记得看到过那么多MonadError,这表明使用它有一些问题

第三种解决方案适用于我的情况,因为管道将是管道的一部分,管道中有一个用户指定的monad(IO),它不应该关心解析错误(它将网络数据解析为用户指定类型的格式)。但它似乎并不那么优雅,而且,(可能?)一旦在任何其他环境中使用,就会导致大量簿记

我还没有真正考虑过最终的解决方案,但它似乎有点复杂

如果您对这个特殊案例有任何想法,我将不胜感激(如果我偏离太远,错过了一些明显的东西,我一点也不会感到惊讶),如果您对管道(-core)/导管/三通e.t.c中错误处理的讨论有任何(或多或少相关的)参考,我将不胜感激

编辑:
另一种可能是采取一种单一的行动(而不是完全吹制的烟斗),尽管我不确定它是否只是泛化、专门化,甚至等同于第四种行动。

如果可以的话,我想我可以通过这样描述选择来帮助组织大家对这一点的想法。你可以:

  • 管道
    EitherT
    /
    error
    内:

    e(管道a b m)r

  • 管道
    EitherT
    /
    错误
    外部:

    管道a b(EitherT e m)r

  • 您需要前一种方法,它还有一个很好的特性,即您可以将其作为MonadError的实例(如果您喜欢的话)

    为了理解这两种方法之间的差异,第二种方法在整个管道级别抛出错误。第一种方法允许在单个管道的粒度上进行错误处理,并正确处理组合管道

    现在来看一些代码。如果你不介意的话,我会用它,因为我更喜欢它:

    import Control.Error
    import Control.Pipe
    
    type PipeE e a b m r = EitherT e (Pipe a b m) r
    
    runPipeE = runPipe . runEitherT
    
    p1 <?< p2 = EitherT (runEitherT p1 <+< runEitherT p2)
    
    导入控制。错误
    导入控制。管道
    类型管道e a b m r=e(管道a b m)r
    runPipe=runPipe。鲁尼瑟特
    
    p1我要指出的是,提案3(使用
    error e m a
    )完全包含在我个人最喜欢的提案2(使用
    MonadError
    )中。但我真的不知道如何客观地回答这个问题。我已经给加布里埃尔发了电子邮件通知他这一点,因为他是和包的作者;大概他一直在考虑这两件事,可能是一起考虑的。@DanielWagner我同意这似乎是上述问题的最佳解决方案。问题是,我总是喜欢引入额外的类型类;尤其是对于那些不仅仅是美化运算符重载的事情。@DanBurton我刚刚意识到我以前忘记说谢谢了!:)很好地减少/简化了问题,并就在这种特殊情况下应用何种方法提出了很好的建议,完美!