Changes between Version 1 and Version 2 of Ticket #110


Ignore:
Timestamp:
Apr 25, 2006 5:52:36 PM (8 years ago)
Author:
brianh@…
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • Ticket #110 – Description

    v1 v2  
    1 One nice way to structure programs is to use monad transformers on top of IO.  For example, one common technique is to use StateT or ReaderT to propigate custom state through IO code.  This technique has two problems 
     1One nice way to structure programs is to use monad transformers on top of IO.  For example, one common technique is to use StateT or ReaderT to propagate custom state through IO code.  This technique has two problems 
    22 
    331) It requires one to use 'liftIO' rather a lot, which is mildly irritating 
     
    1717}}} 
    1818 
    19 This allows one to use custom monads built on IO and still do correct exception handling, etc. without haveing to do lots of nasty monad unwrapping/rewrapping. 
     19This allows one to use custom monads built on IO and still do correct exception handling, etc. without having to do lots of nasty monad unwrapping/rewrapping. 
    2020 
    2121NOTE: This is not possible to implement. there is no way to 'rewind' a monad 
    2222in a generic way in order to implement try or catch. - JohnMeacham 
    2323 
     24NOTE: An alternative is to use a different version of Control.Exception that defines a typeclass as follows: 
     25{{{ 
     26class MonadIO m => MonadException m where 
     27    catch :: m a -> (Exception -> m a) -> m a 
    2428 
     29    block, unblock :: m a -> m a 
     30}}} 
     31This can be implemented for the common monad transformers, and all the other exception functions can be implemented just using the methods in the above typeclass, or using liftIO with the existing functions. A full implementation (not fully tested though) is attached. -- Brian Hulley 
     32 
     33NOTE: Even though not all uses of IO can be eliminated (eg when defining callback functions to use with FFI), the importance of having an Exception module which is not tied to concrete {{{IO}}} is that it would allow library writers which require {{{block}}}, {{{bracket}}} etc to use the more general {{{MonadException}}} in place of {{{IO}}}. If library writers do not do this, users of the library, which may be other libraries etc, are also tied down to concrete {{{IO}}}, so the longer we leave it, the more difficult it will be to "unconcretise" the code base.  -- Brian Hulley 
    2534 
    2635More radical proposal: 
     
    4453 
    4554Now you can eliminate a bunch of noisy calls to liftIO in client code. 
     55 
     56NOTE: This should be quite trivial to implement for all functions which just use {{{IO}}} in the return value. When {{{IO}}} is used in other positions it is unlikely to be possible to implement except by replacing the other occurrence of {{{IO}}} by {{{MonadIOU}}} defined by: 
     57{{{ 
     58     class MonadIO m => MonadIOU m where 
     59       getUnliftIO :: m (m a -> IO a) 
     60}}} 
     61Unfortunately only a few of the monad transformers support this operation (eg {{{ReaderT}}} ) but at least it's better than nothing. An alternative would be to define special typeclasses for related sets of operations if this would allow more monad transformers to be supported by the particular operations, or to add first-order api functions which a library user could use to build a specialised version of the higher order function for a specific monad. -- Brian Hulley