For better or for worse, Haskell's popular Servant library has made it common-place to run code in a monad transformer stack involving ExceptT err IO
. Servant's own handler monad is ExceptT ServantErr IO
. As many argue, this is a somewhat troublesome monad to work in since there are multiple ways for failure to unroll: 1) via normal exceptions from IO
at the base, or 2) by returning Left
.
As Ed Kmett's exceptions
library helpfully clarifies:
Continuation-based monads, and stacks such as
ErrorT e IO
which provide for multiple failure modes, are invalid instances of this [MonadMask
] class.
This is very inconvenient since MonadMask
gives us access the helpful [polymorphic version of] bracket
function for doing resource management (not leaking resources due to an exception, etc.). But in Servant's Handler
monad we can't use it.
I'm not very familiar with it, but some people say that the solution is to use monad-control
and it's many partner libraries like lifted-base
and lifted-async
to give your monad access to resource management tools like bracket
(presumably this works for ExceptT err IO
and friends as well?).
However, it seems that monad-control
is losing favor in the community, yet I can't tell what the alternative would be. Even Snoyman's recent safe-exceptions
library uses Kmett's exceptions
library and avoids monad-control
.
Can someone clarify the current story for people like me who are trying to plow our way into serious Haskell usage?