Changes between Version 1 and Version 2 of Ticket #110


Ignore:
Timestamp:
Apr 25, 2006 5:52:36 PM (9 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