
Hi all, The function 'block' and 'unblock' (from Control.Exception) have been deprecated for some time, and are apparantly now being removed (in favour of 'mask'). Generalisations of these functions are (part of) the interface of MonadCatchIO-transformers (the 'MonadCatchIO' class has methods 'block' and 'unblock'). So, the interface would have to change to keep up with base. I'm inclined to deprecate MonadCatchIO-transformers itself, in favour of monad-control. I suspect that most clients do not use 'block' or 'unblock' directly, but use only derived functions, like 'bracket'. (I have partly confirmed this, by inspecting some reverse dependencies on hackage.) This allow an easy transition to monad-control: in many cases, only imports will need to be changed. In the minority of cases where 'block' and 'unblock' are used and/or instances of MonadCatchIO are defined, code will need to be updated. There is a difference in functionality between MonadCatchIO and monad-control. In the former, 'bracket' will not perform the final action if the main action is an ErrorT that throws an error (in contrast with exceptions in the underlying IO monad). In monad-control, 'bracket' will perform the final action in this case. (See this discussion for background: http://www.haskell.org/pipermail/haskell-cafe/2010-October/084890.html.) Probably, in most use cases the behaviour of monad-control is preferred. This seems to be the case also for snap, which uses MonadCatchIO-transformers, but defines its own variant of 'bracket' to get the right behaviour. Would anyone have a problem with a deprecation of MonadCatchIO-transformers, and a failure to update it to work with a base without 'block' and 'unblock'? Regards, Arie

Arie Peterson
Would anyone have a problem with a deprecation of MonadCatchIO-transformers, and a failure to update it to work with a base without 'block' and 'unblock'?
Yes. This is a simplified variant of a monad I use: newtype Continue f m a = Continue (m (Maybe a, f (Continue f a))) It's related to Cofree and has a valid and very straightforward MonadCatchIO instance. However, it's probably impossible to write a valid MonadTransControl/MonadBaseControl instance for it. So I kindly ask you not to deprecate MonadCatchIO. The reason I'm hesitant about moving to monad-control is that it's hard to understand and also very difficult to define for CPS monads. It is commonly believed to be impossible. Also I've seen at least one article about the incorrectness of monad-control. That's one further reason I like to avoid it. Greets, Ertugrul -- Not to be or to be and (not to be or to be and (not to be or to be and (not to be or to be and ... that is the list monad.

Ertugrul Söylemez
newtype Continue f m a = Continue (m (Maybe a, f (Continue f a)))
Typo: newtype Continue f m a = Continue (m (Maybe a, f (Continue f m a))) Sorry. Greets, Ertugrul -- Not to be or to be and (not to be or to be and (not to be or to be and (not to be or to be and ... that is the list monad.

On Sun, Mar 3, 2013 at 6:07 PM, Ertugrul Söylemez
Arie Peterson
wrote: Would anyone have a problem with a deprecation of MonadCatchIO-transformers, and a failure to update it to work with a base without 'block' and 'unblock'?
Yes. This is a simplified variant of a monad I use:
newtype Continue f m a = Continue (m (Maybe a, f (Continue f a)))
It's related to Cofree and has a valid and very straightforward MonadCatchIO instance. However, it's probably impossible to write a valid MonadTransControl/MonadBaseControl instance for it.
Perhaps there's a good reason why it's impossible to make such an instance. Are you sure that your MonadCatchIO instance is well founded? What happens if you use finally? Are you guaranteed that your cleanup function is called once, and precisely once? These are the problems I ran into with MonadCatchIO three years ago, almost precisely. The main monad for Yesod was built around ContT, and I ended up with double-free bugs. It's true that I had to move away from ContT in order to get the desired semantics, but that has nothing to do with MonadCatchIO vs monad-control. The former just made it seem like I had working code when in fact I had a lurking bug.
So I kindly ask you not to deprecate MonadCatchIO. The reason I'm hesitant about moving to monad-control is that it's hard to understand and also very difficult to define for CPS monads. It is commonly believed to be impossible.
Also I've seen at least one article about the incorrectness of monad-control. That's one further reason I like to avoid it.
I've seen the criticisms of monad-control (or at least I believe I have). What I've seen has been dubious at best. I'll fully agree that the implementation is hard to follow, but it's designed for efficiency. The underlying concept is simple: capture the current state and pipe it through the underlying monad. If you needed to lift a control operation for the ReaderT or StateT monads, you would likely end up with an almost exact replica of what monad-control does for you. Michael

On Sunday 03 March 2013 17:07:18 Ertugrul Söylemez wrote:
Would anyone have a problem with a deprecation of MonadCatchIO-transformers, and a failure to update it to work with a base without 'block' and 'unblock'?
Yes. This is a simplified variant of a monad I use:
newtype Continue f m a = Continue (m (Maybe a, f (Continue f a)))
It's related to Cofree and has a valid and very straightforward MonadCatchIO instance. However, it's probably impossible to write a valid MonadTransControl/MonadBaseControl instance for it.
Is it possibly to write the equivalent of Control.Exception.mask for it? That would be the first candidate for replacing block and unblock in the MonadCatchIO class. Regards, Arie

On Mon, Mar 4, 2013 at 12:07 AM, Ertugrul Söylemez
Arie Peterson
wrote: Would anyone have a problem with a deprecation of MonadCatchIO-transformers, and a failure to update it to work with a base without 'block' and 'unblock'?
Yes. This is a simplified variant of a monad I use:
newtype Continue f m a = Continue (m (Maybe a, f (Continue f a)))
It's related to Cofree and has a valid and very straightforward MonadCatchIO instance. However, it's probably impossible to write a valid MonadTransControl/MonadBaseControl instance for it.
So I kindly ask you not to deprecate MonadCatchIO. The reason I'm hesitant about moving to monad-control is that it's hard to understand and also very difficult to define for CPS monads. It is commonly believed to be impossible.
You can always cast the continuation to a dynamic type and cast it back later. Doing so would typically require additional constraints, however if you're trying to make an instance for MonadTransControl that's unfortunately not possible (you'd need a Typeable constraint on the monad parameter, but it's not in scope). Lacking an appropriate MonadTransControlWithTypeable class, it's certainly possible to fall back to various low-level, highly-dubious constructs. Which I of course implemented without hesitation :grin
Also I've seen at least one article about the incorrectness of monad-control. That's one further reason I like to avoid it.
I'd appreciate a link if anyone could manage to find it. I haven't seen any criticisms of monad-control. John L.

Also I've seen at least one article about the incorrectness of
monad-control. That's one further reason I like to avoid it.
I'd appreciate a link if anyone could manage to find it. I haven't seen any criticisms of monad-control.
Oddly, I just stumbled across http://blog.ezyang.com/2012/01/monadbasecontrol-is-unsound/ from a mostly-unrelated search. Was this the article to which you're referring?

While block and unblock have been removed from base, they are still implementable in modern GHC. So another possible future is to deprecate MonadCatchIO (which should have been done a while ago, honestly!), but manually redefine the functions so that old code keeps working. Edward Excerpts from Arie Peterson's message of Sun Mar 03 07:40:06 -0800 2013:
Hi all,
The function 'block' and 'unblock' (from Control.Exception) have been deprecated for some time, and are apparantly now being removed (in favour of 'mask').
Generalisations of these functions are (part of) the interface of MonadCatchIO-transformers (the 'MonadCatchIO' class has methods 'block' and 'unblock'). So, the interface would have to change to keep up with base.
I'm inclined to deprecate MonadCatchIO-transformers itself, in favour of monad-control.
I suspect that most clients do not use 'block' or 'unblock' directly, but use only derived functions, like 'bracket'. (I have partly confirmed this, by inspecting some reverse dependencies on hackage.) This allow an easy transition to monad-control: in many cases, only imports will need to be changed. In the minority of cases where 'block' and 'unblock' are used and/or instances of MonadCatchIO are defined, code will need to be updated.
There is a difference in functionality between MonadCatchIO and monad-control. In the former, 'bracket' will not perform the final action if the main action is an ErrorT that throws an error (in contrast with exceptions in the underlying IO monad). In monad-control, 'bracket' will perform the final action in this case. (See this discussion for background: http://www.haskell.org/pipermail/haskell-cafe/2010-October/084890.html.)
Probably, in most use cases the behaviour of monad-control is preferred. This seems to be the case also for snap, which uses MonadCatchIO-transformers, but defines its own variant of 'bracket' to get the right behaviour.
Would anyone have a problem with a deprecation of MonadCatchIO-transformers, and a failure to update it to work with a base without 'block' and 'unblock'?
Regards,
Arie
participants (5)
-
Arie Peterson
-
Edward Z. Yang
-
Ertugrul Söylemez
-
John Lato
-
Michael Snoyman