(This question is similar to this question but that question only received a comment recommending the errors package, I would like some more details.)
I'm working on a program that uses two different packages that both return types IO (Either e a) or Either e a. However the e is not the same between the libraries.
I wonder how to structure functions that use both libraries. The hint that I should use errors led me to hush and note, but this doesn't feel quite right:
data MyError = Error1 | Error2 | Error3
f :: IO (Either MyErrorType Text)
f = do
  now <- someIoAction
  runExceptT $ do
    x <- note Error1 $ hush LibraryA.f
    y <- ExceptT $ note Error2 . hush <$> LibraryB.IO.f
    z <- ExceptT $ note Error3 . hush <$> LibraryB.IO.g
    pure (x, y, z)
How should one structure code like this? Should I match on results and convert the error types? Are there something else in the errors package that I should know about? I will be really grateful for an answer to the (somewhat) specific question about how to structure code like the one above and general pointers to dealing with non-uniform errors in Haskell.
                        
If you want to handle the error only once, I'd transform
IO (Either e a)intoIO awith a utility function like this:This looks dangerous at a glance, but it's useful in some (very common, IMO) cases:
IO aor someEither e a.