monad-control 0.2.0.3 → 0.3
raw patch · 8 files changed
+365/−980 lines, 8 filesdep +transformers-basedep −HUnitdep −test-frameworkdep −test-framework-hunitdep ~basesetup-changedPVP ok
version bump matches the API change (PVP)
Dependencies added: transformers-base
Dependencies removed: HUnit, test-framework, test-framework-hunit
Dependency ranges changed: base
API changes (from Hackage documentation)
- Control.Exception.Control: Handler :: (e -> m α) -> Handler m α
- Control.Exception.Control: bracket :: MonadControlIO m => m α -> (α -> m β) -> (α -> m γ) -> m γ
- Control.Exception.Control: bracketOnError :: MonadControlIO m => m α -> (α -> m β) -> (α -> m γ) -> m γ
- Control.Exception.Control: bracket_ :: MonadControlIO m => m α -> m β -> m γ -> m γ
- Control.Exception.Control: catch :: (MonadControlIO m, Exception e) => m α -> (e -> m α) -> m α
- Control.Exception.Control: catchJust :: (MonadControlIO m, Exception e) => (e -> Maybe β) -> m α -> (β -> m α) -> m α
- Control.Exception.Control: catches :: MonadControlIO m => m α -> [Handler m α] -> m α
- Control.Exception.Control: data Handler m α
- Control.Exception.Control: evaluate :: MonadIO m => α -> m α
- Control.Exception.Control: finally :: MonadControlIO m => m α -> m β -> m α
- Control.Exception.Control: getMaskingState :: MonadIO m => m MaskingState
- Control.Exception.Control: handle :: (MonadControlIO m, Exception e) => (e -> m α) -> m α -> m α
- Control.Exception.Control: handleJust :: (MonadControlIO m, Exception e) => (e -> Maybe β) -> (β -> m α) -> m α -> m α
- Control.Exception.Control: ioError :: MonadIO m => IOError -> m α
- Control.Exception.Control: mask :: MonadControlIO m => ((forall α. m α -> m α) -> m β) -> m β
- Control.Exception.Control: mask_ :: MonadControlIO m => m α -> m α
- Control.Exception.Control: onException :: MonadControlIO m => m α -> m β -> m α
- Control.Exception.Control: throwIO :: (MonadIO m, Exception e) => e -> m α
- Control.Exception.Control: try :: (MonadControlIO m, Exception e) => m α -> m (Either e α)
- Control.Exception.Control: tryJust :: (MonadControlIO m, Exception e) => (e -> Maybe β) -> m α -> m (Either β α)
- Control.Exception.Control: uninterruptibleMask :: MonadControlIO m => ((forall α. m α -> m α) -> m β) -> m β
- Control.Exception.Control: uninterruptibleMask_ :: MonadControlIO m => m α -> m α
- Control.Monad.IO.Control: class MonadIO m => MonadControlIO m
- Control.Monad.IO.Control: controlIO :: MonadControlIO m => (RunInBase m IO -> IO (m α)) -> m α
- Control.Monad.IO.Control: instance (Error e, MonadControlIO m) => MonadControlIO (ErrorT e m)
- Control.Monad.IO.Control: instance (Monoid w, MonadControlIO m) => MonadControlIO (RWST r w s m)
- Control.Monad.IO.Control: instance (Monoid w, MonadControlIO m) => MonadControlIO (WriterT w m)
- Control.Monad.IO.Control: instance MonadControlIO IO
- Control.Monad.IO.Control: instance MonadControlIO m => MonadControlIO (IdentityT m)
- Control.Monad.IO.Control: instance MonadControlIO m => MonadControlIO (ListT m)
- Control.Monad.IO.Control: instance MonadControlIO m => MonadControlIO (MaybeT m)
- Control.Monad.IO.Control: instance MonadControlIO m => MonadControlIO (ReaderT r m)
- Control.Monad.IO.Control: instance MonadControlIO m => MonadControlIO (StateT s m)
- Control.Monad.IO.Control: liftControlIO :: MonadControlIO m => (RunInBase m IO -> IO α) -> m α
- Control.Monad.IO.Control: liftIOOp :: MonadControlIO m => ((α -> IO (m β)) -> IO (m γ)) -> ((α -> m β) -> m γ)
- Control.Monad.IO.Control: liftIOOp_ :: MonadControlIO m => (IO (m α) -> IO (m β)) -> (m α -> m β)
- Control.Monad.Trans.Control: idLiftControl :: Monad m => (RunInBase m m -> m α) -> m α
- Control.Monad.Trans.Control: liftControl :: (MonadTransControl t, Monad m) => (Run t -> m α) -> t m α
- Control.Monad.Trans.Control: liftLiftControlBase :: (MonadTransControl t, Monad (t m), Monad m, Monad base) => ((RunInBase m base -> base α) -> m α) -> ((RunInBase (t m) base -> base α) -> t m α)
+ Control.Monad.Trans.Control: class MonadBase b m => MonadBaseControl b m | m -> b where { data family StM m :: * -> *; }
+ Control.Monad.Trans.Control: defaultLiftBaseWith :: (MonadTransControl t, MonadBaseControl b m) => (forall β. ComposeSt t m β -> StM (t m) β) -> ((RunInBase (t m) b -> b α) -> t m α)
+ Control.Monad.Trans.Control: defaultRestoreM :: (MonadTransControl t, MonadBaseControl b m) => (StM (t m) α -> ComposeSt t m α) -> (StM (t m) α -> t m α)
+ Control.Monad.Trans.Control: instance (Error e, MonadBaseControl b m) => MonadBaseControl b (ErrorT e m)
+ Control.Monad.Trans.Control: instance (Monoid w, MonadBaseControl b m) => MonadBaseControl b (RWST r w s m)
+ Control.Monad.Trans.Control: instance (Monoid w, MonadBaseControl b m) => MonadBaseControl b (WriterT w m)
+ Control.Monad.Trans.Control: instance MonadBaseControl ((->) r) ((->) r)
+ Control.Monad.Trans.Control: instance MonadBaseControl (Either e) (Either e)
+ Control.Monad.Trans.Control: instance MonadBaseControl (ST s) (ST s)
+ Control.Monad.Trans.Control: instance MonadBaseControl IO IO
+ Control.Monad.Trans.Control: instance MonadBaseControl Identity Identity
+ Control.Monad.Trans.Control: instance MonadBaseControl Maybe Maybe
+ Control.Monad.Trans.Control: instance MonadBaseControl STM STM
+ Control.Monad.Trans.Control: instance MonadBaseControl [] []
+ Control.Monad.Trans.Control: instance MonadBaseControl b m => MonadBaseControl b (IdentityT m)
+ Control.Monad.Trans.Control: instance MonadBaseControl b m => MonadBaseControl b (ListT m)
+ Control.Monad.Trans.Control: instance MonadBaseControl b m => MonadBaseControl b (MaybeT m)
+ Control.Monad.Trans.Control: instance MonadBaseControl b m => MonadBaseControl b (ReaderT r m)
+ Control.Monad.Trans.Control: instance MonadBaseControl b m => MonadBaseControl b (StateT s m)
+ Control.Monad.Trans.Control: liftBaseDiscard :: MonadBaseControl b m => (b () -> b α) -> (m () -> m α)
+ Control.Monad.Trans.Control: liftBaseOp :: MonadBaseControl b m => ((α -> b (StM m β)) -> b (StM m γ)) -> ((α -> m β) -> m γ)
+ Control.Monad.Trans.Control: liftBaseOp_ :: MonadBaseControl b m => (b (StM m α) -> b (StM m β)) -> (m α -> m β)
+ Control.Monad.Trans.Control: liftBaseWith :: MonadBaseControl b m => (RunInBase m b -> b α) -> m α
+ Control.Monad.Trans.Control: liftWith :: (MonadTransControl t, Monad m) => (Run t -> m α) -> t m α
+ Control.Monad.Trans.Control: restoreM :: MonadBaseControl b m => StM m α -> m α
+ Control.Monad.Trans.Control: restoreT :: (MonadTransControl t, Monad m) => m (StT t α) -> t m α
+ Control.Monad.Trans.Control: type ComposeSt t m α = StM m (StT t α)
- Control.Monad.Trans.Control: class MonadTrans t => MonadTransControl t
+ Control.Monad.Trans.Control: class MonadTrans t => MonadTransControl t where { data family StT t :: * -> *; }
- Control.Monad.Trans.Control: control :: (Monad m, Monad (t m), MonadTransControl t) => (Run t -> m (t m α)) -> t m α
+ Control.Monad.Trans.Control: control :: MonadBaseControl b m => (RunInBase m b -> b (StM m α)) -> m α
- Control.Monad.Trans.Control: type RunInBase m base = forall β. m β -> base (m β)
+ Control.Monad.Trans.Control: type RunInBase m b = forall α. m α -> b (StM m α)
- Control.Monad.Trans.Control: type Run t = forall n o β. (Monad n, Monad o, Monad (t o)) => t n β -> n (t o β)
+ Control.Monad.Trans.Control: type Run t = forall n β. Monad n => t n β -> n (StT t β)
Files
- Control/Exception/Control.hs +0/−362
- Control/Monad/IO/Control.hs +0/−180
- Control/Monad/Trans/Control.hs +329/−184
- NEWS +8/−0
- README.markdown +1/−3
- Setup.hs +2/−44
- monad-control.cabal +25/−48
- test.hs +0/−159
− Control/Exception/Control.hs
@@ -1,362 +0,0 @@-{-# LANGUAGE CPP, UnicodeSyntax, NoImplicitPrelude, ExistentialQuantification #-}--#if MIN_VERSION_base(4,3,0)-{-# LANGUAGE RankNTypes #-} -- for mask-#endif--{- |-Module : Control.Exception.Control-Copyright : Bas van Dijk, Anders Kaseorg-License : BSD-style--Maintainer : Bas van Dijk <v.dijk.bas@gmail.com>-Stability : experimental-Portability : non-portable (extended exceptions)--This is a wrapped version of @Control.Exception@ with types generalized-from @IO@ to all monads in 'MonadControlIO'.--}--module Control.Exception.Control- ( module Control.Exception-- -- * Throwing exceptions- , throwIO, ioError-- -- * Catching exceptions- -- ** The @catch@ functions- , catch, catches, Handler(..), catchJust-- -- ** The @handle@ functions- , handle, handleJust-- -- ** The @try@ functions- , try, tryJust-- -- ** The @evaluate@ function- , evaluate-- -- * Asynchronous Exceptions- -- ** Asynchronous exception control- -- |The following functions allow a thread to control delivery of- -- asynchronous exceptions during a critical region.-#if MIN_VERSION_base(4,3,0)- , mask, mask_- , uninterruptibleMask, uninterruptibleMask_- , getMaskingState-#else- , block, unblock-#endif--#if !MIN_VERSION_base(4,4,0)- , blocked-#endif- -- * Brackets- , bracket, bracket_, bracketOnError-- -- * Utilities- , finally, onException- ) where-------------------------------------------------------------------------------------- Imports------------------------------------------------------------------------------------- from base:-import Data.Function ( ($) )-import Data.Either ( Either(Left, Right), either )-import Data.Maybe ( Maybe )-import Control.Monad ( Monad, (>>=), return, liftM )-import System.IO.Error ( IOError )--#if MIN_VERSION_base(4,3,0) || defined (__HADDOCK__)-import System.IO ( IO )-#endif--#if __GLASGOW_HASKELL__ < 700-import Control.Monad ( fail )-#endif---- from base-unicode-symbols:-import Data.Function.Unicode ( (∘) )---- from transformers:-import Control.Monad.IO.Class ( MonadIO, liftIO )--import Control.Exception hiding- ( throwIO, ioError- , catch, catches, Handler(..), catchJust- , handle, handleJust- , try, tryJust- , evaluate-#if MIN_VERSION_base(4,3,0)- , mask, mask_- , uninterruptibleMask, uninterruptibleMask_- , getMaskingState-#else- , block, unblock-#endif-#if !MIN_VERSION_base(4,4,0)- , blocked-#endif- , bracket, bracket_, bracketOnError- , finally, onException- )-import qualified Control.Exception as E--#if !MIN_VERSION_base(4,4,0)-import Data.Bool ( Bool )-#endif---- from monad-control (this package):-import Control.Monad.IO.Control ( MonadControlIO- , controlIO- , liftIOOp_- )-#if MIN_VERSION_base(4,3,0) || defined (__HADDOCK__)-import Control.Monad.IO.Control ( liftIOOp )-#endif------------------------------------------------------------------------------------- * Throwing exceptions------------------------------------------------------------------------------------- |Generalized version of 'E.throwIO'.-throwIO ∷ (MonadIO m, Exception e) ⇒ e → m α-throwIO = liftIO ∘ E.throwIO---- |Generalized version of 'E.ioError'.-ioError ∷ MonadIO m ⇒ IOError → m α-ioError = liftIO ∘ E.ioError-------------------------------------------------------------------------------------- * Catching exceptions------------------------------------------------------------------------------------- |Generalized version of 'E.catch'.-{-# INLINABLE catch #-}-catch ∷ (MonadControlIO m, Exception e)- ⇒ m α -- ^ The computation to run- → (e → m α) -- ^ Handler to invoke if an exception is raised- → m α-catch a handler = controlIO $ \runInIO →- E.catch (runInIO a)- (\e → runInIO $ handler e)---- |Generalized version of 'E.catches'.-{-# INLINABLE catches #-}-catches ∷ MonadControlIO m ⇒ m α → [Handler m α] → m α-catches a handlers = controlIO $ \runInIO →- E.catches (runInIO a)- [ E.Handler $ \e → runInIO $ handler e- | Handler handler ← handlers- ]---- |Generalized version of 'E.Handler'.-data Handler m α = ∀ e. Exception e ⇒ Handler (e → m α)---- |Generalized version of 'E.catchJust'.-{-# INLINABLE catchJust #-}-catchJust ∷ (MonadControlIO m, Exception e)- ⇒ (e → Maybe β) -- ^ Predicate to select exceptions- → m α -- ^ Computation to run- → (β → m α) -- ^ Handler- → m α-catchJust p a handler = controlIO $ \runInIO →- E.catchJust p- (runInIO a)- (\e → runInIO (handler e))-------------------------------------------------------------------------------------- ** The @handle@ functions------------------------------------------------------------------------------------- |Generalized version of 'E.handle'.-{-# INLINABLE handle #-}-handle ∷ (MonadControlIO m, Exception e) ⇒ (e → m α) → m α → m α-handle handler a = controlIO $ \runInIO →- E.handle (\e → runInIO (handler e))- (runInIO a)---- |Generalized version of 'E.handleJust'.-{-# INLINABLE handleJust #-}-handleJust ∷ (MonadControlIO m, Exception e)- ⇒ (e → Maybe β) → (β → m α) → m α → m α-handleJust p handler a = controlIO $ \runInIO →- E.handleJust p (\e → runInIO (handler e))- (runInIO a)-------------------------------------------------------------------------------------- ** The @try@ functions-----------------------------------------------------------------------------------sequenceEither ∷ Monad m ⇒ Either e (m α) → m (Either e α)-sequenceEither = either (return ∘ Left) (liftM Right)---- |Generalized version of 'E.try'.-{-# INLINABLE try #-}-try ∷ (MonadControlIO m, Exception e) ⇒ m α → m (Either e α)-try = liftIOOp_ (liftM sequenceEither ∘ E.try)---- |Generalized version of 'E.tryJust'.-{-# INLINABLE tryJust #-}-tryJust ∷ (MonadControlIO m, Exception e) ⇒- (e → Maybe β) → m α → m (Either β α)-tryJust p = liftIOOp_ (liftM sequenceEither ∘ E.tryJust p)-------------------------------------------------------------------------------------- ** The @evaluate@ function------------------------------------------------------------------------------------- |Generalized version of 'E.evaluate'.-evaluate ∷ MonadIO m ⇒ α → m α-evaluate = liftIO ∘ E.evaluate-------------------------------------------------------------------------------------- ** Asynchronous exception control-----------------------------------------------------------------------------------#if MIN_VERSION_base(4,3,0)--- |Generalized version of 'E.mask'.-{-# INLINABLE mask #-}-mask ∷ MonadControlIO m ⇒ ((∀ α. m α → m α) → m β) → m β-mask = liftIOOp E.mask ∘ liftRestore--liftRestore ∷ MonadControlIO m- ⇒ ((∀ α. m α → m α) → β)- → ((∀ α. IO α → IO α) → β)-liftRestore f restore = f $ liftIOOp_ restore---- |Generalized version of 'E.mask_'.-{-# INLINABLE mask_ #-}-mask_ ∷ MonadControlIO m ⇒ m α → m α-mask_ = liftIOOp_ E.mask_---- |Generalized version of 'E.uninterruptibleMask'.-{-# INLINABLE uninterruptibleMask #-}-uninterruptibleMask ∷ MonadControlIO m ⇒ ((∀ α. m α → m α) → m β) → m β-uninterruptibleMask = liftIOOp E.uninterruptibleMask ∘ liftRestore---- |Generalized version of 'E.uninterruptibleMask_'.-{-# INLINABLE uninterruptibleMask_ #-}-uninterruptibleMask_ ∷ MonadControlIO m ⇒ m α → m α-uninterruptibleMask_ = liftIOOp_ E.uninterruptibleMask_---- |Generalized version of 'E.getMaskingState'.-getMaskingState ∷ MonadIO m ⇒ m MaskingState-getMaskingState = liftIO E.getMaskingState-#else--- |Generalized version of 'E.block'.-{-# INLINABLE block #-}-block ∷ MonadControlIO m ⇒ m α → m α-block = liftIOOp_ E.block---- |Generalized version of 'E.unblock'.-{-# INLINABLE unblock #-}-unblock ∷ MonadControlIO m ⇒ m α → m α-unblock = liftIOOp_ E.unblock-#endif--#if !MIN_VERSION_base(4,4,0)--- | Generalized version of 'E.blocked'.--- returns @True@ if asynchronous exceptions are blocked in the--- current thread.-blocked ∷ MonadIO m ⇒ m Bool-blocked = liftIO E.blocked-#endif-------------------------------------------------------------------------------------- * Brackets------------------------------------------------------------------------------------- |Generalized version of 'E.bracket'. Note, any monadic side--- effects in @m@ of the \"release\" computation will be discarded; it--- is run only for its side effects in @IO@.------ Note that when your @acquire@ and @release@ computations are of type 'IO'--- it will be more efficient to write:------ @'liftIOOp' ('E.bracket' acquire release)@-{-# INLINABLE bracket #-}-bracket ∷ MonadControlIO m- ⇒ m α -- ^ computation to run first (\"acquire resource\")- → (α → m β) -- ^ computation to run last (\"release resource\")- → (α → m γ) -- ^ computation to run in-between- → m γ-bracket before after thing = controlIO $ \runInIO →- E.bracket (runInIO before)- (\m → runInIO $ m >>= after)- (\m → runInIO $ m >>= thing)---- |Generalized version of 'E.bracket_'. Note, any monadic side--- effects in @m@ of /both/ the \"acquire\" and \"release\"--- computations will be discarded. To keep the monadic side effects--- of the \"acquire\" computation, use 'bracket' with constant--- functions instead.------ Note that when your @acquire@ and @release@ computations are of type 'IO'--- it will be more efficient to write:------ @'liftIOOp_' ('E.bracket_' acquire release)@-{-# INLINABLE bracket_ #-}-bracket_ ∷ MonadControlIO m- ⇒ m α -- ^ computation to run first (\"acquire resource\")- → m β -- ^ computation to run last (\"release resource\")- → m γ -- ^ computation to run in-between- → m γ-bracket_ before after thing = controlIO $ \runInIO →- E.bracket_ (runInIO before)- (runInIO after)- (runInIO thing)---- |Generalized version of 'E.bracketOnError'. Note, any monadic side--- effects in @m@ of the \"release\" computation will be discarded.------ Note that when your @acquire@ and @release@ computations are of type 'IO'--- it will be more efficient to write:------ @'liftIOOp' ('E.bracketOnError' acquire release)@-{-# INLINABLE bracketOnError #-}-bracketOnError ∷ MonadControlIO m- ⇒ m α -- ^ computation to run first (\"acquire resource\")- → (α → m β) -- ^ computation to run last (\"release resource\")- → (α → m γ) -- ^ computation to run in-between- → m γ-bracketOnError before after thing = controlIO $ \runInIO →- E.bracketOnError (runInIO before)- (\m → runInIO $ m >>= after)- (\m → runInIO $ m >>= thing)-------------------------------------------------------------------------------------- * Utilities------------------------------------------------------------------------------------- |Generalized version of 'E.finally'. Note, any monadic side--- effects in @m@ of the \"afterward\" computation will be discarded.-{-# INLINABLE finally #-}-finally ∷ MonadControlIO m- ⇒ m α -- ^ computation to run first- → m β -- ^ computation to run afterward (even if an exception was raised)- → m α-finally a sequel = controlIO $ \runInIO →- E.finally (runInIO a)- (runInIO sequel)---- |Generalized version of 'E.onException'. Note, any monadic side--- effects in @m@ of the \"afterward\" computation will be discarded.-{-# INLINABLE onException #-}-onException ∷ MonadControlIO m ⇒ m α → m β → m α-onException m what = controlIO $ \runInIO →- E.onException (runInIO m)- (runInIO what)----- The End ---------------------------------------------------------------------
− Control/Monad/IO/Control.hs
@@ -1,180 +0,0 @@-{-# 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)- @-- Instances should satisfy similar laws as the 'MonadIO' laws:-- @liftControlIO . const . return = return@-- @liftControlIO (const (m >>= f)) = liftControlIO (const m) >>= liftControlIO . const . f@-- Additionally instances should satisfy:-- @'controlIO' $ \\runInIO -> runInIO m = m@- -}- liftControlIO ∷ (RunInBase m IO → IO α) → m α---- | An often used composition: @controlIO = 'join' . 'liftControlIO'@-{-# INLINABLE controlIO #-}-controlIO ∷ MonadControlIO m ⇒ (RunInBase m IO → IO (m α)) → m α-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@--}-{-# INLINABLE liftIOOp #-}-liftIOOp ∷ MonadControlIO m- ⇒ ((α → IO (m β)) → IO (m γ))- → ((α → m β) → m γ)-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@--}-{-# INLINABLE liftIOOp_ #-}-liftIOOp_ ∷ MonadControlIO m- ⇒ (IO (m α) → IO (m β))- → ( m α → m β)-liftIOOp_ f = \m → controlIO $ \runInIO → f $ runInIO m----- The End ---------------------------------------------------------------------
Control/Monad/Trans/Control.hs view
@@ -1,4 +1,12 @@-{-# LANGUAGE UnicodeSyntax, NoImplicitPrelude, RankNTypes #-}+{-# LANGUAGE CPP+ , UnicodeSyntax+ , NoImplicitPrelude+ , RankNTypes+ , TypeFamilies+ , FunctionalDependencies+ , FlexibleInstances+ , UndecidableInstances+ #-} {- | Module : Control.Monad.Trans.Control@@ -7,28 +15,29 @@ Maintainer : Bas van Dijk <v.dijk.bas@gmail.com> Stability : experimental-Portability : Requires RankNTypes -This module defines the class 'MonadTransControl' of monad transformers-through which control operations can be lifted. Instances are-included for all the standard monad transformers from the-@transformers@ library except @ContT@.--'idLiftControl' and 'liftLiftControlBase' are provided to assist creation of-@MonadControlIO@-like classes (see "Control.Monad.IO.Control") based on core-monads other than 'IO'.+(TODO: It would be nicer if the associated /data types/ 'StT' and 'StM' were+associated /type synonyms/ instead. This would simplify a lot of code and could+make some definitions more efficient because there'll be no need to wrap the+monadic state in a data type. Unfortunately GHC has a bug which prevents this:+<http://hackage.haskell.org/trac/ghc/ticket/5595>. I will switch to associated+type synonyms when that bug is fixed.) -} module Control.Monad.Trans.Control- ( -- * MonadTransControl- MonadTransControl(..)- , Run+ ( MonadTransControl(..), Run+ , MonadBaseControl (..), RunInBase++ -- * Defaults for MonadBaseControl+ -- $defaults+ , ComposeSt, defaultLiftBaseWith, defaultRestoreM++ -- * Utility functions , control - -- * Lifting- , idLiftControl- , RunInBase- , liftLiftControlBase+ , liftBaseOp, liftBaseOp_++ , liftBaseDiscard ) where @@ -37,15 +46,23 @@ -------------------------------------------------------------------------------- -- from base:-import Data.Function ( ($) )+import Data.Function ( ($), const ) import Data.Monoid ( Monoid, mempty )-import Control.Monad ( Monad, join, return, liftM )+import Control.Monad ( Monad, (>>=), return, liftM, void ) +import System.IO ( IO )+import GHC.Conc.Sync ( STM )+import Data.Maybe ( Maybe )+import Data.Either ( Either )++import Control.Monad.ST.Lazy ( ST )+import qualified Control.Monad.ST.Strict as Strict ( ST )+ -- from base-unicode-symbols: import Data.Function.Unicode ( (∘) ) -- from transformers:-import Control.Monad.Trans.Class ( MonadTrans, lift )+import Control.Monad.Trans.Class ( MonadTrans ) import Control.Monad.Trans.Identity ( IdentityT(IdentityT), runIdentityT ) import Control.Monad.Trans.List ( ListT (ListT), runListT )@@ -60,216 +77,344 @@ import qualified Control.Monad.Trans.State.Strict as Strict ( StateT (StateT), runStateT ) import qualified Control.Monad.Trans.Writer.Strict as Strict ( WriterT(WriterT), runWriterT ) +import Data.Functor.Identity ( Identity ) +-- from transformers-base:+import Control.Monad.Base ( MonadBase )++ ----------------------------------------------------------------------------------- MonadTransControl+-- MonadTransControl type class -------------------------------------------------------------------------------- -{-|-@MonadTransControl@ is the class of monad transformers supporting an-extra operation 'liftControl', enabling control operations (functions that-use monadic actions as input instead of just output) to be lifted-through the transformer.--} class MonadTrans t ⇒ MonadTransControl t where- {-|- @liftControl@ is used to peel off the outer layer of a transformed- monadic action, allowing an transformed action @t m a@ to be- treated as a base action @m a@.-- More precisely, @liftControl@ captures the monadic state of @t@ at the- point where it is bound (in @t m@), yielding a function of type:-- @'Run' t = forall n o b. (Monad n, Monad o) => t n b -> n (t o b)@-- This function runs a transformed monadic action @t n b@- in the inner monad @n@ using the captured state, and leaves the- result @t o b@ in the monad @n@ after all side effects in @n@- have occurred.-- This can be used to lift control operations with types such as- @M a -> M a@ into the transformed monad @t M@:-- @- instance Monad M- foo :: M a -> M a- foo' :: ('MonadTransControl' t, 'Monad' (t M)) => t M a -> t M a- foo' a = 'control' $ \run -> -- run :: t M a -> M (t M a)- foo $ run a -- uses foo :: M (t M a) -> M (t M a)- @-- Instances should satisfy similar laws as the 'MonadTrans' laws:-- @liftControl . const . return = return@-- @liftControl (const (m >>= f)) = liftControl (const m) >>= liftControl . const . f@-- Additionally instances should satisfy:+ -- | Monadic state of @t@.+ data StT t ∷ * → * - @'control' $ \\run -> run t = t@- -}- liftControl ∷ Monad m ⇒ (Run t → m α) → t m α+ -- | @liftWith@ is similar to 'lift' in that it lifts a computation from+ -- the argument monad to the constructed monad.+ --+ -- Instances should satisfy similar laws as the 'MonadTrans' laws:+ --+ -- @liftWith . const . return = return@+ --+ -- @liftWith (const (m >>= f)) = liftWith (const m) >>= liftWith . const . f@+ --+ -- The difference with 'lift' is that before lifting the @m@ computation+ -- @liftWith@ captures the state of @t@. It then provides the @m@+ -- computation with a 'Run' function that allows running @t n@ computations in+ -- @n@ (for all @n@) on the captured state.+ liftWith ∷ Monad m ⇒ (Run t → m α) → t m α -type Run t = ∀ n o β- . (Monad n, Monad o, Monad (t o))- ⇒ t n β → n (t o β)+ -- | Construct a @t@ computation from the monadic state of @t@ that is+ -- returned from a 'Run' function.+ --+ -- Instances should satisfy:+ --+ -- @liftWith (\\run -> run t) >>= restoreT . return = t@+ restoreT ∷ Monad m ⇒ m (StT t α) → t m α --- | An often used composition: @control = 'join' . 'liftControl'@-control ∷ (Monad m, Monad (t m), MonadTransControl t)- ⇒ (Run t → m (t m α)) → t m α-control = join ∘ liftControl+-- | A function that runs a transformed monad @t n@ on the monadic state that+-- was captured by 'liftWith'+--+-- A @Run t@ function yields a computation in @n@ that returns the monadic state+-- of @t@. This state can later be used to restore a @t@ computation using+-- 'restoreT'.+type Run t = ∀ n β. Monad n ⇒ t n β → n (StT t β) ----------------------------------------------------------------------------------- Instances+-- MonadTransControl instances -------------------------------------------------------------------------------- instance MonadTransControl IdentityT where- liftControl f = IdentityT $ f run- where- run t = liftM return (runIdentityT t)+ newtype StT IdentityT α = StId {unStId ∷ α}+ liftWith f = IdentityT $ f $ liftM StId ∘ runIdentityT+ restoreT = IdentityT ∘ liftM unStId+ {-# INLINE liftWith #-}+ {-# INLINE restoreT #-} -instance Error e ⇒- MonadTransControl (ErrorT e) where liftControl = liftControlNoState ErrorT runErrorT-instance MonadTransControl ListT where liftControl = liftControlNoState ListT runListT-instance MonadTransControl MaybeT where liftControl = liftControlNoState MaybeT runMaybeT+instance MonadTransControl MaybeT where+ newtype StT MaybeT α = StMaybe {unStMaybe ∷ Maybe α}+ liftWith f = MaybeT $ liftM return $ f $ liftM StMaybe ∘ runMaybeT+ restoreT = MaybeT ∘ liftM unStMaybe+ {-# INLINE liftWith #-}+ {-# INLINE restoreT #-} -liftControlNoState ∷ (Monad m, Monad f)- ⇒ (∀ p β. p (f β) → t p β)- → (∀ n β. t n β → n (f β))- → ((Run t → m α) → t m α)-liftControlNoState mkT runT = \f → mkT $ liftM return $ f $- liftM (mkT ∘ return) ∘ runT+instance Error e ⇒ MonadTransControl (ErrorT e) where+ newtype StT (ErrorT e) α = StError {unStError ∷ Either e α}+ liftWith f = ErrorT $ liftM return $ f $ liftM StError ∘ runErrorT+ restoreT = ErrorT ∘ liftM unStError+ {-# INLINE liftWith #-}+ {-# INLINE restoreT #-} +instance MonadTransControl ListT where+ newtype StT ListT α = StList {unStList ∷ [α]}+ liftWith f = ListT $ liftM return $ f $ liftM StList ∘ runListT+ restoreT = ListT ∘ liftM unStList+ {-# INLINE liftWith #-}+ {-# INLINE restoreT #-}+ instance MonadTransControl (ReaderT r) where- liftControl f =- ReaderT $ \r →- let run t = liftM return (runReaderT t r)- in f run+ newtype StT (ReaderT r) α = StReader {unStReader ∷ α}+ liftWith f = ReaderT $ \r → f $ \t → liftM StReader $ runReaderT t r+ restoreT = ReaderT ∘ const ∘ liftM unStReader+ {-# INLINE liftWith #-}+ {-# INLINE restoreT #-} instance MonadTransControl (StateT s) where- liftControl f =- StateT $ \s →- let run t = liftM (\ ~(x, s') → StateT $ \_ → return (x, s'))- (runStateT t s)- in liftM (\x → (x, s)) (f run)+ newtype StT (StateT s) α = StState {unStState ∷ (α, s)}+ liftWith f = StateT $ \s →+ liftM (\x → (x, s))+ (f $ \t → liftM StState $ runStateT t s)+ restoreT = StateT ∘ const ∘ liftM unStState+ {-# INLINE liftWith #-}+ {-# INLINE restoreT #-} instance MonadTransControl (Strict.StateT s) where- liftControl f =- Strict.StateT $ \s →- let run t = liftM (\(x, s') → Strict.StateT $ \_ → return (x, s'))- (Strict.runStateT t s)- in liftM (\x → (x, s)) (f run)+ newtype StT (Strict.StateT s) α = StState' {unStState' ∷ (α, s)}+ liftWith f = Strict.StateT $ \s →+ liftM (\x → (x, s))+ (f $ \t → liftM StState' $ Strict.runStateT t s)+ restoreT = Strict.StateT ∘ const ∘ liftM unStState'+ {-# INLINE liftWith #-}+ {-# INLINE restoreT #-} instance Monoid w ⇒ MonadTransControl (WriterT w) where- liftControl f = WriterT $ liftM (\x → (x, mempty)) (f run)- where- run t = liftM (\ ~(x, w) → WriterT $ return (x, w))- (runWriterT t)+ newtype StT (WriterT w) α = StWriter {unStWriter ∷ (α, w)}+ liftWith f = WriterT $ liftM (\x → (x, mempty))+ (f $ liftM StWriter ∘ runWriterT)+ restoreT = WriterT ∘ liftM unStWriter+ {-# INLINE liftWith #-}+ {-# INLINE restoreT #-} instance Monoid w ⇒ MonadTransControl (Strict.WriterT w) where- liftControl f = Strict.WriterT $ liftM (\x → (x, mempty)) (f run)- where- run t = liftM (\(x, w) → Strict.WriterT $ return (x, w))- (Strict.runWriterT t)+ newtype StT (Strict.WriterT w) α = StWriter' {unStWriter' ∷ (α, w)}+ liftWith f = Strict.WriterT $ liftM (\x → (x, mempty))+ (f $ liftM StWriter' ∘ Strict.runWriterT)+ restoreT = Strict.WriterT ∘ liftM unStWriter'+ {-# INLINE liftWith #-}+ {-# INLINE restoreT #-} instance Monoid w ⇒ MonadTransControl (RWST r w s) where- liftControl f =- RWST $ \r s →- let run t = liftM (\ ~(x, s', w) → RWST $ \_ _ → return (x, s', w))- (runRWST t r s)- in liftM (\x → (x, s, mempty)) (f run)+ newtype StT (RWST r w s) α = StRWS {unStRWS ∷ (α, s, w)}+ liftWith f = RWST $ \r s → liftM (\x → (x, s, mempty))+ (f $ \t → liftM StRWS $ runRWST t r s)+ restoreT mSt = RWST $ \_ _ → liftM unStRWS mSt+ {-# INLINE liftWith #-}+ {-# INLINE restoreT #-} instance Monoid w ⇒ MonadTransControl (Strict.RWST r w s) where- liftControl f =- Strict.RWST $ \r s →- let run t = liftM (\(x, s', w) → Strict.RWST $ \_ _ → return (x, s', w))- (Strict.runRWST t r s)- in liftM (\x → (x, s, mempty)) (f run)+ newtype StT (Strict.RWST r w s) α = StRWS' {unStRWS' ∷ (α, s, w)}+ liftWith f =+ Strict.RWST $ \r s → liftM (\x → (x, s, mempty))+ (f $ \t → liftM StRWS' $ Strict.runRWST t r s)+ restoreT mSt = Strict.RWST $ \_ _ → liftM unStRWS' mSt+ {-# INLINE liftWith #-}+ {-# INLINE restoreT #-} ----------------------------------------------------------------------------------- Lifting+-- MonadBaseControl type class -------------------------------------------------------------------------------- -{-|-@idLiftControl@ acts as the \"identity\" 'liftControl' operation from a monad-@m@ to itself.+class MonadBase b m ⇒ MonadBaseControl b m | m → b where+ -- | Monadic state of @m@.+ data StM m ∷ * → * -@idLiftControl f = f $ liftM return@+ -- | @liftBaseWith@ is similar to 'liftIO' and 'liftBase' in that it+ -- lifts a base computation to the constructed monad.+ --+ -- Instances should satisfy similar laws as the 'MonadIO' and 'MonadBase' laws:+ --+ -- @liftBaseWith . const . return = return@+ --+ -- @liftBaseWith (const (m >>= f)) = liftBaseWith (const m) >>= liftBaseWith . const . f@+ --+ -- The difference with 'liftBase' is that before lifting the base computation+ -- @liftBaseWith@ captures the state of @m@. It then provides the base+ -- computation with a 'RunInBase' function that allows running @m@+ -- computations in the base monad on the captured state.+ liftBaseWith ∷ (RunInBase m b → b α) → m α -It serves as the base case for a class like @MonadControlIO@, which-allows control operations in some base monad (here @IO@) to be-lifted through arbitrary stacks of zero or more monad transformers-in one call. For example, "Control.Monad.IO.Control" defines:+ -- | Construct a @m@ computation from the monadic state of @m@ that is+ -- returned from a 'RunInBase' function.+ --+ -- Instances should satisfy:+ --+ -- @liftBaseWith (\\runInBase -> runInBase m) >>= restoreM = m@+ restoreM ∷ StM m α → m α -@-class MonadIO m => MonadControlIO m where- liftControlIO :: (RunInBase m IO -> IO b) -> m b-@+-- | A function that runs a @m@ computation on the monadic state that was+-- captured by 'liftBaseWith'+--+-- A @RunInBase m@ function yields a computation in the base monad of @m@ that+-- returns the monadic state of @m@. This state can later be used to restore the+-- @m@ computation using 'restoreM'.+type RunInBase m b = ∀ α. m α → b (StM m α) -@-instance MonadControlIO IO where- liftControlIO = idLiftControl-@--}-idLiftControl ∷ Monad m ⇒ (RunInBase m m → m α) → m α-idLiftControl f = f $ liftM return -type RunInBase m base = ∀ β. m β → base (m β)+--------------------------------------------------------------------------------+-- MonadBaseControl instances for all monads in the base library+-------------------------------------------------------------------------------- -{-|-@liftLiftControlBase@ is used to compose two 'liftControl' operations:-the outer provided by a 'MonadTransControl' instance,-and the inner provided as the argument.+#define BASE(M, ST) \+instance MonadBaseControl (M) (M) where { \+ newtype StM (M) α = ST α; \+ liftBaseWith f = f $ liftM ST; \+ restoreM (ST x) = return x; \+ {-# INLINE liftBaseWith #-}; \+ {-# INLINE restoreM #-}} -It satisfies @'liftLiftControlBase' 'idLiftControl' = 'liftControl'@.+BASE(IO, StIO)+BASE(Strict.ST s, StSTS)+BASE( ST s, StST)+BASE(STM, StSTM)+BASE(Maybe, St)+BASE(Either e, StE)+BASE([], StL)+BASE((→) r, StF)+BASE(Identity, StI)+#undef BASE -It serves as the induction step of a @MonadControlIO@-like class. For-example, "Control.Monad.IO.Control" defines: -@-instance MonadControlIO m => MonadControlIO (StateT s m) where- liftControlIO = liftLiftControlBase liftControlIO-@+--------------------------------------------------------------------------------+-- Defaults for MonadBaseControl+-------------------------------------------------------------------------------- -using the 'MonadTransControl' instance of @'StateT' s@.+-- $defaults+--+-- Note that by using the following default definitions it's easy to make a+-- monad transformer @T@ an instance of 'MonadBaseControl':+--+-- @+-- instance MonadBaseControl b m => MonadBaseControl b (T m) where+-- newtype StM (T m) a = StMT {unStMT :: 'ComposeSt' T m a}+-- liftBaseWith = 'defaultLiftBaseWith' StMT+-- restoreM = 'defaultRestoreM' unStMT+-- @+--+-- Defining an instance for a base monad @B@ is equally straightforward:+--+-- @+-- instance MonadBaseControl B B where+-- newtype StM B a = StMB {unStMB :: a}+-- liftBaseWith f = f $ liftM StMB+-- restoreM = return . unStMB+-- @ -The following shows the recursive structure of 'liftControlIO' applied to a-stack of three monad transformers with IO as the base monad: @t1 (t2 (t3 IO)) a@:+-- | Handy type synonym that composes the monadic states of @t@ and @m@.+--+-- It can be used to define the 'StM' for new 'MonadBaseControl' instances.+type ComposeSt t m α = StM m (StT t α) -@-liftControlIO- =- 'liftLiftControlBase' $- 'liftLiftControlBase' $- 'liftLiftControlBase' $- 'idLiftControl'- =- \\f -> 'liftControl' $ \\run1 -> -- Capture state of t1, run1 :: 'Run' t1- 'liftControl' $ \\run2 -> -- Capture state of t2, run2 :: 'Run' t2- 'liftControl' $ \\run3 -> -- Capture state of t3, run3 :: 'Run' t3- let run :: 'RunInBase' (t1 (t2 (t3 IO))) IO- run = -- Restore state- 'liftM' ('join' . 'lift') -- :: IO ( t2 (t3 IO) (t1 (t2 (t3 IO)) a)) -> IO ( t1 (t2 (t3 IO)) a)- . 'liftM' ('join' . 'lift') -- :: IO ( t3 IO (t2 (t3 IO) (t1 (t2 (t3 IO)) a))) -> IO ( t2 (t3 IO) (t1 (t2 (t3 IO)) a))- -- Identity conversion- . 'liftM' ('join' . 'lift') -- :: IO (IO (t3 IO (t2 (t3 IO) (t1 (t2 (t3 IO)) a)))) -> IO ( t3 IO (t2 (t3 IO) (t1 (t2 (t3 IO)) a)))- . 'liftM' 'return' -- :: IO ( t3 IO (t2 (t3 IO) (t1 (t2 (t3 IO)) a))) -> IO (IO (t3 IO (t2 (t3 IO) (t1 (t2 (t3 IO)) a))))- -- Run (computation to run:) (inner monad:) (restore computation:)- . run3 -- :: t3 IO (t2 (t3 IO) (t1 (t2 (t3 IO)) a)) -> IO (t3 IO (t2 (t3 IO) (t1 (t2 (t3 IO)) a)))- . run2 -- :: t2 (t3 IO) (t1 (t2 (t3 IO)) a) -> t3 IO (t2 (t3 IO) (t1 (t2 (t3 IO)) a))- . run1 -- :: t1 (t2 (t3 IO)) a -> t2 (t3 IO) (t1 (t2 (t3 IO)) a)- in f run-@--}-liftLiftControlBase ∷ (MonadTransControl t, Monad (t m), Monad m, Monad base)- ⇒ ((RunInBase m base → base α) → m α) -- ^ @liftControlBase@ operation- → ((RunInBase (t m) base → base α) → t m α)-liftLiftControlBase lftCtrlBase = \f → liftControl $ \run1 →- lftCtrlBase $ \runInBase →- let run = liftM (join ∘ lift) ∘ runInBase ∘ run1- in f run+-- | Default defintion for the 'liftBaseWith' method.+--+-- Note that it composes a 'liftWith' of @t@ with a 'liftBaseWith' of @m@ to+-- give a 'liftBaseWith' of @t m@:+--+-- @+-- defaultLiftBaseWith stM = \\f -> 'liftWith' $ \\run ->+-- 'liftBaseWith' $ \\runInBase ->+-- f $ liftM stM . runInBase . run+-- @+defaultLiftBaseWith ∷ (MonadTransControl t, MonadBaseControl b m)+ ⇒ (∀ β. ComposeSt t m β → StM (t m) β) -- ^ 'StM' constructor+ → ((RunInBase (t m) b → b α) → t m α)+defaultLiftBaseWith stM = \f → liftWith $ \run →+ liftBaseWith $ \runInBase →+ f $ liftM stM ∘ runInBase ∘ run+{-# INLINE defaultLiftBaseWith #-} +-- | Default definition for the 'restoreM' method.+--+-- Note that: @defaultRestoreM unStM = 'restoreT' . 'restoreM' . unStM@+defaultRestoreM ∷ (MonadTransControl t, MonadBaseControl b m)+ ⇒ (StM (t m) α → ComposeSt t m α) -- ^ 'StM' deconstructor+ → (StM (t m) α → t m α)+defaultRestoreM unStM = restoreT ∘ restoreM ∘ unStM+{-# INLINE defaultRestoreM #-} --- The End ---------------------------------------------------------------------++--------------------------------------------------------------------------------+-- MonadBaseControl transformer instances+--------------------------------------------------------------------------------++#define BODY(T, ST, unST) { \+ newtype StM (T m) α = ST {unST ∷ ComposeSt (T) m α}; \+ liftBaseWith = defaultLiftBaseWith ST; \+ restoreM = defaultRestoreM unST; \+ {-# INLINE liftBaseWith #-}; \+ {-# INLINE restoreM #-}}++#define TRANS( T, ST, unST) \+ instance ( MonadBaseControl b m) ⇒ MonadBaseControl b (T m) where BODY(T, ST, unST)+#define TRANS_CTX(CTX, T, ST, unST) \+ instance (CTX, MonadBaseControl b m) ⇒ MonadBaseControl b (T m) where BODY(T, ST, unST)++TRANS(IdentityT, StMId, unStMId)+TRANS(MaybeT, StMMaybe, unStMMaybe)+TRANS(ListT, StMList, unStMList)+TRANS(ReaderT r, StMReader, unStMReader)+TRANS(Strict.StateT s, StMStateS, unStMStateS)+TRANS( StateT s, StMState, unStMState)++TRANS_CTX(Error e, ErrorT e, StMError, unStMError)+TRANS_CTX(Monoid w, Strict.WriterT w, StMWriterS, unStMWriterS)+TRANS_CTX(Monoid w, WriterT w, StMWriter, unStMWriter)+TRANS_CTX(Monoid w, Strict.RWST r w s, StMRWSS, unStMRWSS)+TRANS_CTX(Monoid w, RWST r w s, StMRWS, unStMRWS)+++--------------------------------------------------------------------------------+-- * Utility functions+--------------------------------------------------------------------------------++-- | An often used composition: @control f = 'liftBaseWith' f >>= 'restoreM'@+control ∷ MonadBaseControl b m ⇒ (RunInBase m b → b (StM m α)) → m α+control f = liftBaseWith f >>= restoreM+{-# INLINE control #-}++-- | @liftBaseOp@ is a particular application of 'liftBaseWith' that allows+-- lifting control operations of type:+--+-- @((a -> b c) -> b c)@ to: @('MonadBaseControl' b m => (a -> m c) -> m c)@.+--+-- For example:+--+-- @liftBaseOp alloca :: 'MonadBaseControl' 'IO' m => (Ptr a -> m c) -> m c@+liftBaseOp ∷ MonadBaseControl b m+ ⇒ ((α → b (StM m β)) → b (StM m γ))+ → ((α → m β) → m γ)+liftBaseOp f = \g → control $ \runInBase → f $ runInBase ∘ g+{-# INLINE liftBaseOp #-}++-- | @liftBaseOp_@ is a particular application of 'liftBaseWith' that allows+-- lifting control operations of type:+--+-- @(b a -> b a)@ to: @('MonadBaseControl' b m => m a -> m a)@.+--+-- For example:+--+-- @liftBaseOp_ mask_ :: 'MonadBaseControl' 'IO' m => m a -> m a@+liftBaseOp_ ∷ MonadBaseControl b m+ ⇒ (b (StM m α) → b (StM m β))+ → ( m α → m β)+liftBaseOp_ f = \m → control $ \runInBase → f $ runInBase m+{-# INLINE liftBaseOp_ #-}++-- | @liftBaseDiscard@ is a particular application of 'liftBaseWith' that allows+-- lifting control operations of type:+--+-- @(b () -> b a)@ to: @('MonadBaseControl' b m => m () -> m a)@.+--+-- Note that, while the argument computation @m ()@ has access to the captured+-- state, all its side-effects in @m@ are discarded. It is run only for its+-- side-effects in the base monad @b@.+--+-- For example:+--+-- @liftBaseDiscard forkIO :: 'MonadBaseControl' 'IO' m => m () -> m ThreadId@+liftBaseDiscard ∷ MonadBaseControl b m ⇒ (b () → b α) → (m () → m α)+liftBaseDiscard f = \m → liftBaseWith $ \runInBase → f $ void $ runInBase m+{-# INLINE liftBaseDiscard #-}
NEWS view
@@ -1,3 +1,11 @@+0.2.0.3++(Released on: Sat Aug 27 21:18:22 UTC 2011)++* Fixed issue #2+ https://github.com/basvandijk/monad-control/issues/2++ 0.2.0.2 (Released on: Mon Aug 8 09:16:08 UTC 2011)
README.markdown view
@@ -2,9 +2,7 @@ `MonadIO` into which generic control operations such as `catch` can be lifted from `IO`. Instances are based on monad transformers in `MonadTransControl`, which includes all standard monad transformers in-the `transformers` library except `ContT`. For convenience, it-provides a wrapped version of `Control.Exception` with types-generalized from `IO` to all monads in `MonadControlIO`.+the `transformers` library except `ContT`. Note that this package is a rewrite of Anders Kaseorg's `monad-peel` library. The main difference is that this package provides CPS style
Setup.hs view
@@ -1,44 +1,2 @@-#! /usr/bin/env runhaskell--{-# LANGUAGE NoImplicitPrelude, UnicodeSyntax #-}--module Main (main) where------------------------------------------------------------------------------------- Imports------------------------------------------------------------------------------------ from base-import System.IO ( IO )---- from cabal-import Distribution.Simple ( defaultMainWithHooks- , simpleUserHooks- , UserHooks(haddockHook)- )--import Distribution.Simple.LocalBuildInfo ( LocalBuildInfo(..) )-import Distribution.Simple.Program ( userSpecifyArgs )-import Distribution.Simple.Setup ( HaddockFlags )-import Distribution.PackageDescription ( PackageDescription(..) )------------------------------------------------------------------------------------- Cabal setup program which sets the CPP define '__HADDOCK __' when haddock is run.----------------------------------------------------------------------------------main ∷ IO ()-main = defaultMainWithHooks hooks- where- hooks = simpleUserHooks { haddockHook = haddockHook' }---- Define __HADDOCK__ for CPP when running haddock.-haddockHook' ∷ PackageDescription → LocalBuildInfo → UserHooks → HaddockFlags → IO ()-haddockHook' pkg lbi =- haddockHook simpleUserHooks pkg (lbi { withPrograms = p })- where- p = userSpecifyArgs "haddock" ["--optghc=-D__HADDOCK__"] (withPrograms lbi)----- The End ---------------------------------------------------------------------+import Distribution.Simple+main = defaultMain
monad-control.cabal view
@@ -1,44 +1,39 @@ Name: monad-control-Version: 0.2.0.3+Version: 0.3 Synopsis: Lift control operations, like exception catching, through monad transformers-Description:- This package defines the type class @MonadControlIO@, a subset of- @MonadIO@ into which generic control operations such as @catch@ can- be lifted from @IO@. Instances are based on monad transformers in- @MonadTransControl@, which includes all standard monad transformers- in the @transformers@ library except @ContT@. For convenience, it- provides a wrapped version of @Control.Exception@ with types- generalized from @IO@ to all monads in @MonadControlIO@.- .- Note that this package is a rewrite of Anders Kaseorg's @monad-peel@ library.- The main difference is that this package provides CPS style- operators and exploits the @RankNTypes@ language extension to- simplify most definitions.- .- The package includes a copy of the @monad-peel@ testsuite written by Anders Kaseorg.- The tests can be performed by using @cabal test@.- .- The following @critertion@ based benchmark shows that @monad-control@- is on average about 2.5 times faster than @monad-peel@:- .- <https://github.com/basvandijk/bench-monad-peel-control>- License: BSD3 License-file: LICENSE Author: Bas van Dijk, Anders Kaseorg Maintainer: Bas van Dijk <v.dijk.bas@gmail.com> Copyright: (c) 2011 Bas van Dijk, Anders Kaseorg-Homepage: https://github.com/basvandijk/monad-control/+Homepage: https://github.com/basvandijk/monad-control Bug-reports: https://github.com/basvandijk/monad-control/issues Category: Control-Build-type: Custom-Cabal-version: >= 1.9.2+Build-type: Simple+Cabal-version: >= 1.6+Description:+ This package defines the type class @MonadBaseControl@, a subset of+ @MonadBase@ into which generic control operations such as @catch@ can be+ lifted from @IO@ or any other base monad. Instances are based on monad+ transformers in @MonadTransControl@, which includes all standard monad+ transformers in the @transformers@ library except @ContT@.+ .+ See the @lifted-base@ package which uses @monad-control@ to lift @IO@+ operations from the @base@ library (like @catch@ or @bracket@) into any monad+ that is an instance of @MonadBase@ or @MonadBaseControl@.+ .+ Note that this package is a rewrite of Anders Kaseorg's @monad-peel@+ library. The main difference is that this package provides CPS style operators+ and exploits the @RankNTypes@ and @TypeFamilies@ language extensions to+ simplify and speedup most definitions.+ .+ The following @critertion@ based benchmark shows that @monad-control@ is on+ average about 99% faster than @monad-peel@:+ .+ @git clone <https://github.com/basvandijk/bench-monad-peel-control>@ extra-source-files: README.markdown, NEWS --- TODO: Remove when http://hackage.haskell.org/trac/hackage/ticket/792 is fixed:-extra-source-files: test.hs- -------------------------------------------------------------------------------- source-repository head@@ -49,28 +44,10 @@ Library Exposed-modules: Control.Monad.Trans.Control- Control.Monad.IO.Control- Control.Exception.Control Build-depends: base >= 3 && < 4.5 , base-unicode-symbols >= 0.1.1 && < 0.3 , transformers >= 0.2 && < 0.3+ , transformers-base >= 0.4 && < 0.5 Ghc-options: -Wall------------------------------------------------------------------------------------test-suite test-threads- type: exitcode-stdio-1.0- main-is: test.hs-- ghc-options: -Wall-- build-depends: base >= 3 && < 4.5- , base-unicode-symbols >= 0.1.1 && < 0.3- , transformers >= 0.2 && < 0.3- , HUnit >= 1.2.2 && < 1.3- , test-framework >= 0.2.4 && < 0.5- , test-framework-hunit >= 0.2.4 && < 0.3----------------------------------------------------------------------------------
− test.hs
@@ -1,159 +0,0 @@-{-# LANGUAGE DeriveDataTypeable #-}---- from base:-import Prelude hiding (catch)-import Data.IORef-import Data.Maybe-import Data.Typeable (Typeable)---- from transformers:-import Control.Monad.IO.Class (liftIO)--import Control.Monad.Trans.Identity-import Control.Monad.Trans.List-import Control.Monad.Trans.Maybe-import Control.Monad.Trans.Reader-import Control.Monad.Trans.Writer-import Control.Monad.Trans.Error-import Control.Monad.Trans.State-import qualified Control.Monad.Trans.RWS as RWS---- from monad-control (this package):-import Control.Exception.Control-import Control.Monad.IO.Control (MonadControlIO)---- from test-framework:-import Test.Framework (defaultMain, testGroup, Test)-- -- from test-framework-hunit:-import Test.Framework.Providers.HUnit---- from hunit:-import Test.HUnit hiding (Test)---main :: IO ()-main = defaultMain- [ testSuite "IdentityT" runIdentityT- , testSuite "ListT" $ fmap head . runListT- , testSuite "MaybeT" $ fmap fromJust . runMaybeT- , testSuite "ReaderT" $ flip runReaderT "reader state"- , testSuite "WriterT" runWriterT'- , testSuite "ErrorT" runErrorT'- , testSuite "StateT" $ flip evalStateT "state state"- , testSuite "RWST" $ \m -> runRWST' m "RWS in" "RWS state"- , testCase "ErrorT throwError" case_throwError- , testCase "WriterT tell" case_tell- ]- where- runWriterT' :: Functor m => WriterT [Int] m a -> m a- runWriterT' = fmap fst . runWriterT- runErrorT' :: Functor m => ErrorT String m () -> m ()- runErrorT' = fmap (either (const ()) id) . runErrorT- runRWST' :: (Monad m, Functor m) => RWS.RWST r [Int] s m a -> r -> s -> m a- runRWST' m r s = fmap fst $ RWS.evalRWST m r s--testSuite :: MonadControlIO m => String -> (m () -> IO ()) -> Test-testSuite s run = testGroup s- [ testCase "finally" $ case_finally run- , testCase "catch" $ case_catch run- , testCase "bracket" $ case_bracket run- , testCase "bracket_" $ case_bracket_ run- , testCase "onException" $ case_onException run- ]--ignore :: IO () -> IO ()-ignore x =- catch x go- where- go :: SomeException -> IO ()- go _ = return ()--data Exc = Exc- deriving (Show, Typeable)-instance Exception Exc--one :: Int-one = 1--case_finally :: MonadControlIO m => (m () -> IO ()) -> Assertion-case_finally run = do- i <- newIORef one- ignore- (run $ (do- liftIO $ writeIORef i 2- error "error") `finally` (liftIO $ writeIORef i 3))- j <- readIORef i- j @?= 3--case_catch :: MonadControlIO m => (m () -> IO ()) -> Assertion-case_catch run = do- i <- newIORef one- run $ (do- liftIO $ writeIORef i 2- throw Exc) `catch` (\Exc -> liftIO $ writeIORef i 3)- j <- readIORef i- j @?= 3--case_bracket :: MonadControlIO m => (m () -> IO ()) -> Assertion-case_bracket run = do- i <- newIORef one- ignore $ run $ bracket- (liftIO $ writeIORef i 2)- (\() -> liftIO $ writeIORef i 4)- (\() -> liftIO $ writeIORef i 3)- j <- readIORef i- j @?= 4--case_bracket_ :: MonadControlIO m => (m () -> IO ()) -> Assertion-case_bracket_ run = do- i <- newIORef one- ignore $ run $ bracket_- (liftIO $ writeIORef i 2)- (liftIO $ writeIORef i 4)- (liftIO $ writeIORef i 3)- j <- readIORef i- j @?= 4--case_onException :: MonadControlIO m => (m () -> IO ()) -> Assertion-case_onException run = do- i <- newIORef one- ignore $ run $ onException- (liftIO (writeIORef i 2) >> error "ignored")- (liftIO $ writeIORef i 3)- j <- readIORef i- j @?= 3- ignore $ run $ onException- (liftIO $ writeIORef i 4)- (liftIO $ writeIORef i 5)- k <- readIORef i- k @?= 4--case_throwError :: Assertion-case_throwError = do- i <- newIORef one- Left "throwError" <- runErrorT $- (liftIO (writeIORef i 2) >> throwError "throwError")- `finally`- (liftIO $ writeIORef i 3)- j <- readIORef i- j @?= 3--case_tell :: Assertion-case_tell = do- i <- newIORef one- ((), w) <- runWriterT $ bracket_- (liftIO (writeIORef i 2) >> tell [1 :: Int])- (liftIO (writeIORef i 4) >> tell [3])- (liftIO (writeIORef i 3) >> tell [2])- j <- readIORef i- j @?= 4- w @?= [2]-- ((), w') <- runWriterT $ bracket- (liftIO (writeIORef i 5) >> tell [5 :: Int])- (const $ liftIO (writeIORef i 7) >> tell [7])- (const $ liftIO (writeIORef i 6) >> tell [6])- j' <- readIORef i- j' @?= 7- w' @?= [5, 6]