On 01/10/2012 11:12 PM, Edward Z. Yang wrote:
Excerpts from Mikhail Vorozhtsov's message of Tue Jan 10 09:54:38 -0500 2012:
On 01/10/2012 12:17 AM, Edward Z. Yang wrote:
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
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.)
Hm, MonadAbort/Recover/Finally are independent (I made MonadAbort a superclass of MonadRecover purely for reasons of convenience). It's easy to imagine monads that have an instance of one of the classes but not of the others.

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.
I certainly didn't do that in any formal way. I was thinking something like this: if we identify the basic IO-specific control operations, abstract them but make sure they interact in the same way they do in IO, then any derivative IO control operation (implemented on top of the basic ones) could be lifted just by changing the type signature. The key words here are of course "interact in the same way".

[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.
Yes, something along those lines. MonadAbort is a generalization of MonadZero, MonadRecover is a specialization of the "left catch" version of MonadPlus (aka MonadOr). MonadFinally is about adopting

finally0 m f = do
  r ← m `morelse` (f Nothing >> mzero)
  (r, ) <$> f (Just r)

to the notion of failure associated with a particular monad.

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to