
Excerpts from Mikhail Vorozhtsov's message of Tue Jan 10 09:54:38 -0500 2012:
Hello Mikhail, Hi.
(Apologies for reviving a two month old thread). Have you put some thought into whether or not these extra classes generalize in a way that is not /quite/ as general as MonadBaseControl (so as to give you the power you need) but still allow you to implement the functionality you are looking for? I'm not sure but it seems something along the lines of unwind-protect ala Scheme might be sufficient. I'm not sure I'm following you. The problem with MonadBaseControl is
On 01/10/2012 12:17 AM, Edward Z. Yang wrote: that it is /not/ general enough.
Sorry, I mispoke. The sense you are using it is "the more general a type class is, the more instances you can write for it." I think the design goal I'm going for here is, "a single signature which covers MonadAbort/Recover/Finally in a way that unifies them." Which is not more general, except in the sense that it "contains" more type classes (certainly not general in the mathematical sense.)
It assumes that you can eject/inject all the stacked effects as a value of some data type. Which works fine for the standard transformers because they are /implemented/ this way. But not for monads that are implemented in operational style, as interpreters, because the interpreter state cannot be internalized. This particular implementation bias causes additional issues when the lifted operation is not fully suited for ejecting/injecting. For example the `Control.Exception.finally` (or unwind-protect), where we can neither inject (at least properly) the effects into nor eject them from the finalizer. That's why I think that the whole "lift operations from the bottom" approach is wrong (the original goal was to lift `Control.Exception`). The right way would be to capture the control semantics of IO as a set of type classes[1] and then implement the general versions of the operations you want to lift. That's what I tried to do with the monad-abord-fd package.
I think this is generally a useful goal, since it helps define the semantics of IO more sharply. However, the exceptions mechanism is actually fairly well specified, as far as semantics go, see "A Semantics for Imprecise Exceptions" and "Asynchronous Exceptions in Haskell." So I'm not sure if monad-abort-fd achieves the goal of expressing these interfaces, in typeclass form, as well as allowing users to interoperate cleanly with existing language support for these facilities.
[1] Which turn out to be quite general: MonadAbort/Recover/Finally are just a twist of MonadZero/MonadPlus
Now that's interesting! Is this an equivalence, e.g. MonadZero/MonadPlus imply MonadAbort/Recover/Finally and vice-versa, or do you need to make some slight modifications? It seems that you somehow need support for multiple zeros of the monad, as well as a way of looking at them.
MonadMask is expectedly more specific, but permits a nice no-op implementation.
(See my earlier comments about asynchronous exceptions.) Cheers, Edward