monad-control-0.1: 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 b) → m b
-- | An often used composition: @controlIO = 'join' . 'liftControlIO'@
controlIO ∷ MonadControlIO m ⇒ (RunInBase m IO → IO (m b)) → m b
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 ---------------------------------------------------------------------