What approach to error handling to use with pipes(-core)?

后端 未结 1 2014
醉酒成梦
醉酒成梦 2020-12-21 05:03

I\'m currently writing some pipes-core/attoparsec plumbing for a small project of mine. I want each parser to give a pipe that awaits ByteString input to the pa

相关标签:
1条回答
  • 2020-12-21 05:37

    If I may, I think I can help organize everybody's thoughts on this by describing the choice like so. You either:

    1. Layer Pipe within an EitherT/ErrorT:

      EitherT e (Pipe a b m) r

    2. Layer Pipe outside of an EitherT/ErrorT:

      Pipe a b (EitherT e m) r

    You want the former approach, which also has the nice property that you can make it an instance of MonadError (if that is your thing).

    To understand the difference between the two approaches, the second one throws errors at the level of the entire pipeline. The first one permits error handling at the granularity of individual pipes and correctly handles composed pipes.

    Now for some code. I'll use EitherT if you don't mind, since I'm more comfortable with it:

    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)
    

    Then just use catchT and throwT within a PipeE to your heart's content.

    This approach has another advantage, which is that you can selectively apply it to certain segments of the pipeline, but then you are responsible for dealing with the potential exceptional value before composing it with other pipes. You could use that flexibility to use exceptional values of different types for different stages of the pipeline or to not use it at all for stages that can't fail and avoid the overhead of error-checking those stages.

    0 讨论(0)
提交回复
热议问题