On 11/14/2011 06:55 AM, Bas van Dijk wrote:
Hi Mikhail,
your type class:
class MonadAbort e μ ⇒ MonadRecover e μ | μ → e where
recover ∷ μ α → (e → μ α) → μ α
looks a lot like the MonadCatchIO type class from MonadCatchIO-transformers:
class MonadIO m => MonadCatchIO m where
catch :: E.Exception e => m a -> (e -> m a) -> m a
I haven't looked at your code in detail but are you sure your
continuation based AIO monad doesn't suffer from the same unexpected
behavior as the ContT monad transformer with regard to catching and
handling exceptions?
Yes, I'm sure. The reason why it works is because finally/bracket/etc
are not implemented on top of 'recover' (i.e. they don't assume that
throwing an exception is the only reason control can escape). The
following class takes care of it:
class (Applicative μ, Monad μ) ⇒ MonadFinally μ where
finally' ∷ μ α → (Maybe α → μ β) → μ (α, β)
finally ∷ μ α → μ β → μ α
finally m = fmap fst . finally' m . const
Finalizers have type 'Maybe α → μ β' so we can
(a) Thread transformer side effects properly:
instance MonadFinally μ ⇒ MonadFinally (L.StateT s μ) where
finally' m f = L.StateT $ \s → do
~(~(mr, _), ~(fr, s'')) ← finally' (L.runStateT m s) $ \mbr → do
let ~(a, s') = case mbr of
Just ~(x, t) → (Just x, t)
Nothing → (Nothing, s)
L.runStateT (f a) s'
return ((mr, fr), s'')
(b) Detect that control escaped computation before producing a result
(finalizer will be called with 'Nothing' in that case).
instance (MonadFinally μ, Error e) ⇒ MonadFinally (ErrorT e μ) where
finally' m f = ErrorT $ do
~(mr, fr) ← finally' (runErrorT m) $ \mbr →
runErrorT $ f $ case mbr of
Just (Right a) → Just a
_ → Nothing
return $ (,) <$> mr <*> fr
That of course does not mean that I can use 'finally' and friends with
ContT, but I can use them with monads which are carefully /implemented/
on top of ContT but do not expose it's full power to the users.
_______________________________________________
Haskell-Cafe mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/haskell-cafe