[Haskell-cafe] Proposal for adding finallyError to MonadError

David Sorokin david.sorokin at gmail.com
Thu Aug 8 14:51:37 CEST 2013

Hi, Café!

I have a proposal. I offer to add a new function to the MonadError type 

   finallyError :: MonadError e m => m a -> m b -> m a

This is a generalization of the standard finally function that has the 
following signature:

   finally: IO a -> IO b -> IO a

Like function finally, the finallyError function runs the first 
computation and then runs the second computation regardless of whether 
an error might arise in the first computation. The first computation 
defines the result.

Introducing semantics of a possible cancellation of the m computation, 
the finallyError function accepts an additional meaning. The second 
computation must be performed even in case of cancelling the 
computation, while function catchError must be ignored. It literally 
means that the finallyError function cannot be expressed in terms of the 
catchError function.

This idea is essentially inspired by the F# async workflow that does 
allow cancelling the Async computation. I implemented a similar monad 
Simulation.Aivika.Cont.Cont for my simulation library Aivika [1]. My 
monad Cont is an extension of the standard monad with the same name. It 
uses continuations (namely, three different continuations within one 
computation). It supports the exception handling and it allows 
cancelling the computation (the liftIO function should also call 
finallyError to catch the possible cancellation event if my Cont was a 
generic monad transformer).

In the simulation the cancellation of the computation (actually, of the 
discontinuous process) is a typical use case. Therefore it should be 
executed as fast as possible. If I raised a specialized IOException for 
the cancellation event, then it would be a more costly operation. This 
is a practical point why the finallyError function cannot be expressed 
in terms of catchError.

Another reason is that the catchError function can eat the cancellation 
exception, which would be absolutely unacceptable. This is a theoretical 
reason for introducing finallyError.

The finallyError function is very useful for guaranteed releasing the 
external resources (such as the modeled entities in Aivika) in case of 
raising an exception and even in case of cancelling the active 
computation, which is important for simulation, for example.

Regarding the standard instances of MonadError, the finallyError 
function seems to be simple for implementing. It is difficult mainly for 
the Cont-based monads. So, in Aivika it is more difficult than 
catchError for my Cont monad.

The actual name of the function is not important but here it looks 
consistent with other functions of the MonadError type class.

Finally, the finallyError function can be actually defined in an 
additional type class, which would extend MonadError like that how the 
ArrowChoice type class extends Arrow.

Kind regards,
David Sorokin

[1] https://github.com/dsorokin/aivika

More information about the Haskell-Cafe mailing list