monad-control-0.2: Control/Monad/IO/Control.hs
{-# LANGUAGE UnicodeSyntax, NoImplicitPrelude, RankNTypes #-}
{- |
Module : Control.Monad.IO.Control
Copyright : © Bas van Dijk, Anders Kaseorg, 2011
License : BSD-style
Maintainer : Bas van Dijk <v.dijk.bas@gmail.com>
Stability : experimental
Portability : Requires RankNTypes
This module defines the class 'MonadControlIO' of 'IO'-based monads into
which control operations on 'IO' (such as exception catching; see
"Control.Exception.Control") can be lifted.
'liftIOOp' and 'liftIOOp_' enable convenient lifting of two common
special cases of control operation types.
-}
module Control.Monad.IO.Control
( MonadControlIO(..)
, controlIO
, liftIOOp
, liftIOOp_
) where
--------------------------------------------------------------------------------
-- Imports
--------------------------------------------------------------------------------
-- from base:
import Data.Function ( ($) )
import Data.Monoid ( Monoid )
import System.IO ( IO )
import Control.Monad ( join )
-- from base-unicode-symbols:
import Data.Function.Unicode ( (∘) )
-- from transformers:
import Control.Monad.IO.Class ( MonadIO )
import Control.Monad.Trans.Identity ( IdentityT )
import Control.Monad.Trans.List ( ListT )
import Control.Monad.Trans.Maybe ( MaybeT )
import Control.Monad.Trans.Error ( ErrorT, Error )
import Control.Monad.Trans.Reader ( ReaderT )
import Control.Monad.Trans.State ( StateT )
import Control.Monad.Trans.Writer ( WriterT )
import Control.Monad.Trans.RWS ( RWST )
import qualified Control.Monad.Trans.State.Strict as Strict ( StateT )
import qualified Control.Monad.Trans.Writer.Strict as Strict ( WriterT )
import qualified Control.Monad.Trans.RWS.Strict as Strict ( RWST )
-- from monad-control (this package):
import Control.Monad.Trans.Control ( idLiftControl
, liftLiftControlBase
, RunInBase
)
--------------------------------------------------------------------------------
-- MonadControlIO
--------------------------------------------------------------------------------
{-|
@MonadControlIO@ is the class of 'IO'-based monads supporting an
extra operation 'liftControlIO', enabling control operations on 'IO' to be
lifted into the monad.
-}
class MonadIO m ⇒ MonadControlIO m where
{-|
@liftControlIO@ is a version of @liftControl@ that operates through an
arbitrary stack of monad transformers directly to an inner 'IO'
(analagously to how 'liftIO' is a version of @lift@). So it can
be used to lift control operations on 'IO' into any
monad in 'MonadControlIO'. For example:
@
foo :: 'IO' a -> 'IO' a
foo' :: 'MonadControlIO' m => m a -> m a
foo' a = 'controlIO' $ \runInIO -> -- runInIO :: m a -> 'IO' (m a)
foo $ runInIO a -- uses foo :: 'IO' (m a) -> 'IO' (m a)
@
-}
liftControlIO ∷ (RunInBase m IO → IO a) → m a
-- | An often used composition: @controlIO = 'join' . 'liftControlIO'@
controlIO ∷ MonadControlIO m ⇒ (RunInBase m IO → IO (m a)) → m a
controlIO = join ∘ liftControlIO
--------------------------------------------------------------------------------
-- Instances
--------------------------------------------------------------------------------
instance MonadControlIO IO where
liftControlIO = idLiftControl
instance MonadControlIO m ⇒ MonadControlIO (IdentityT m) where
liftControlIO = liftLiftControlBase liftControlIO
instance MonadControlIO m ⇒ MonadControlIO (ListT m) where
liftControlIO = liftLiftControlBase liftControlIO
instance MonadControlIO m ⇒ MonadControlIO (MaybeT m) where
liftControlIO = liftLiftControlBase liftControlIO
instance (Error e, MonadControlIO m) ⇒ MonadControlIO (ErrorT e m) where
liftControlIO = liftLiftControlBase liftControlIO
instance MonadControlIO m ⇒ MonadControlIO (ReaderT r m) where
liftControlIO = liftLiftControlBase liftControlIO
instance MonadControlIO m ⇒ MonadControlIO (StateT s m) where
liftControlIO = liftLiftControlBase liftControlIO
instance MonadControlIO m ⇒ MonadControlIO (Strict.StateT s m) where
liftControlIO = liftLiftControlBase liftControlIO
instance (Monoid w, MonadControlIO m) ⇒ MonadControlIO (WriterT w m) where
liftControlIO = liftLiftControlBase liftControlIO
instance (Monoid w, MonadControlIO m) ⇒ MonadControlIO (Strict.WriterT w m) where
liftControlIO = liftLiftControlBase liftControlIO
instance (Monoid w, MonadControlIO m) ⇒ MonadControlIO (RWST r w s m) where
liftControlIO = liftLiftControlBase liftControlIO
instance (Monoid w, MonadControlIO m) ⇒ MonadControlIO (Strict.RWST r w s m) where
liftControlIO = liftLiftControlBase liftControlIO
--------------------------------------------------------------------------------
-- Convenient lifting of two common special cases of control operation types
--------------------------------------------------------------------------------
{-|
@liftIOOp@ is a particular application of 'liftControlIO' that allows
lifting control operations of type @(a -> 'IO' b) -> 'IO' b@
(e.g. @alloca@, @withMVar v@) to
@'MonadControlIO' m => (a -> m b) -> m b@.
@liftIOOp f = \\g -> 'controlIO' $ \runInIO -> f $ runInIO . g@
-}
liftIOOp ∷ MonadControlIO m
⇒ ((a → IO (m b)) → IO (m c))
→ (a → m b) → m c
liftIOOp f = \g → controlIO $ \runInIO → f $ runInIO ∘ g
{-|
@liftIOOp_@ is a particular application of 'liftControlIO' that allows
lifting control operations of type @'IO' a -> 'IO' a@
(e.g. @block@) to @'MonadControlIO' m => m a -> m a@.
@liftIOOp_ f = \\m -> 'controlIO' $ \runInIO -> f $ runInIO m@
-}
liftIOOp_ ∷ MonadControlIO m
⇒ (IO (m a) → IO (m b))
→ m a → m b
liftIOOp_ f = \m → controlIO $ \runInIO → f $ runInIO m
-- The End ---------------------------------------------------------------------