monad-control 0.1 → 0.2
raw patch · 4 files changed
+155/−115 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Control.Monad.Trans.Control: type Run t n o = forall b. t n b -> n (t o b)
+ Control.Monad.Trans.Control: type Run t = forall n o b. (Monad n, Monad o, Monad (t o)) => t n b -> n (t o b)
- Control.Monad.IO.Control: controlIO :: MonadControlIO m => (RunInBase m IO -> IO (m b)) -> m b
+ Control.Monad.IO.Control: controlIO :: MonadControlIO m => (RunInBase m IO -> IO (m a)) -> m a
- Control.Monad.IO.Control: liftControlIO :: MonadControlIO m => (RunInBase m IO -> IO b) -> m b
+ Control.Monad.IO.Control: liftControlIO :: MonadControlIO m => (RunInBase m IO -> IO a) -> m a
- Control.Monad.Trans.Control: control :: (Monad n, Monad m, Monad o, Monad (t m), MonadTransControl t) => (Run t n o -> m (t m a)) -> t m a
+ Control.Monad.Trans.Control: control :: (Monad m, Monad (t m), MonadTransControl t) => (Run t -> m (t m a)) -> t m a
- Control.Monad.Trans.Control: idLiftControl :: Monad m => ((forall b. m b -> m (m b)) -> m a) -> m a
+ Control.Monad.Trans.Control: idLiftControl :: Monad m => (RunInBase m m -> m a) -> m a
- Control.Monad.Trans.Control: liftControl :: (MonadTransControl t, Monad m, Monad n, Monad o) => (Run t n o -> m a) -> t m a
+ Control.Monad.Trans.Control: liftControl :: (MonadTransControl t, Monad m) => (Run t -> m a) -> t m a
- Control.Monad.Trans.Control: liftLiftControlBase :: (MonadTransControl t, Monad base, Monad m, Monad (t m)) => ((RunInBase m base -> base a) -> m a) -> ((RunInBase (t m) base -> base a) -> t m a)
+ Control.Monad.Trans.Control: liftLiftControlBase :: (MonadTransControl t, Monad (t m), Monad m, Monad base) => ((RunInBase m base -> base a) -> m a) -> ((RunInBase (t m) base -> base a) -> t m a)
Files
- Control/Exception/Control.hs +4/−4
- Control/Monad/IO/Control.hs +35/−28
- Control/Monad/Trans/Control.hs +113/−80
- monad-control.cabal +3/−3
Control/Exception/Control.hs view
@@ -169,14 +169,14 @@ E.handleJust p (\e → runInIO (handler e)) (runInIO a) -sequenceEither ∷ Monad m ⇒ Either e (m a) → m (Either e a)-sequenceEither (Left e) = return $ Left e-sequenceEither (Right m) = liftM Right m - -------------------------------------------------------------------------------- -- ** The @try@ functions --------------------------------------------------------------------------------++sequenceEither ∷ Monad m ⇒ Either e (m a) → m (Either e a)+sequenceEither (Left e) = return $ Left e+sequenceEither (Right m) = liftM Right m -- |Generalized version of 'E.try'. try ∷ (MonadControlIO m, Exception e) ⇒ m a → m (Either e a)
Control/Monad/IO/Control.hs view
@@ -66,26 +66,30 @@ -- 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.+{-|+@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+ {-|+ @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 b)) → m b+controlIO ∷ MonadControlIO m ⇒ (RunInBase m IO → IO (m a)) → m a controlIO = join ∘ liftControlIO @@ -134,23 +138,26 @@ -- 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@ 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_@ 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
Control/Monad/Trans/Control.hs view
@@ -65,45 +65,46 @@ -- MonadTransControl -------------------------------------------------------------------------------- --- |@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.+{-|+@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 b@.- --- -- More precisely, @liftControl@ captures the monadic state of @t@ at the- -- point where it is bound (in @t n@), yielding a function of type- -- @'Run' t n o = t n a -> n (t o a)@- -- this function runs a transformed monadic action @t n a@- -- in the base monad @n@ using the captured state, and leaves the- -- result @t o a@ 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)- -- @- --- -- @liftControl@ is typically used with @m == n == o@, but is required to- -- be polymorphic for greater type safety: for example, this type- -- ensures that the result of running the action in @m@ has no- -- remaining side effects in @m@.- liftControl ∷ (Monad m, Monad n, Monad o) ⇒ (Run t n o → m a) → t m a+ {-|+ @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@. -type Run t n o = ∀ b. t n b → n (t o b)+ 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)+ @+ -}+ liftControl ∷ Monad m ⇒ (Run t → m a) → t m a++type Run t = ∀ n o b. (Monad n, Monad o, Monad (t o)) ⇒ t n b → n (t o b)+ -- | An often used composition: @control = 'join' . 'liftControl'@-control ∷ (Monad n, Monad m, Monad o, Monad (t m), MonadTransControl t)- ⇒ (Run t n o → m (t m a)) → t m a+control ∷ (Monad m, Monad (t m), MonadTransControl t)+ ⇒ (Run t → m (t m a)) → t m a control = join ∘ liftControl @@ -121,13 +122,12 @@ instance MonadTransControl ListT where liftControl = liftControlNoState ListT runListT instance MonadTransControl MaybeT where liftControl = liftControlNoState MaybeT runMaybeT -liftControlNoState ∷ (Monad m, Monad n, Monad o, Monad f)- ⇒ (∀ a p. p (f a) → t p a)- → (∀ a. t m a → m (f a))- → (Run t m o → n b) → t n b-liftControlNoState mkT runT = \f → mkT $ liftM return $ f run- where- run = liftM (mkT ∘ return) ∘ runT+liftControlNoState ∷ (Monad m, Monad f)+ ⇒ (∀ p b. p (f b) → t p b)+ → (∀ n b. t n b → n (f b))+ → (Run t → m a) → t m a+liftControlNoState mkT runT = \f → mkT $ liftM return $ f $+ liftM (mkT ∘ return) ∘ runT instance MonadTransControl (ReaderT r) where liftControl f =@@ -178,51 +178,84 @@ -- Lifting -------------------------------------------------------------------------------- --- |@idLiftControl@ acts as the \"identity\" 'liftControl' operation from a monad--- @m@ to itself.------ @idLiftControl f = f $ liftM return@------ 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------ @--- class MonadIO m => MonadControlIO m where--- liftControlIO :: (RunInBase m IO -> IO b) -> m b--- @------ @--- instance MonadControlIO IO where--- liftControlIO = idLiftControl--- @-idLiftControl ∷ Monad m ⇒ ((∀ b. m b → m (m b)) → m a) → m a+{-|+@idLiftControl@ acts as the \"identity\" 'liftControl' operation from a monad+@m@ to itself.++@idLiftControl f = f $ liftM return@++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:++@+class MonadIO m => MonadControlIO m where+ liftControlIO :: (RunInBase m IO -> IO b) -> m b+@++@+instance MonadControlIO IO where+ liftControlIO = idLiftControl+@+-}+idLiftControl ∷ Monad m ⇒ (RunInBase m m → m a) → m a idLiftControl f = f $ liftM return type RunInBase m base = ∀ b. m b → base (m b) --- |@liftLiftControlBase@ is used to compose two 'liftControl' operations:--- the outer provided by a 'MonadTransControl' instance,--- and the inner provided as the argument.------ It satisfies @'liftLiftControlBase' 'idLiftControl' == 'liftControl'@.------ 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--- @------ using the 'MonadTransControl' instance of @'StateT' s@.-liftLiftControlBase ∷ (MonadTransControl t, Monad base, Monad m, Monad (t m))+{-|+@liftLiftControlBase@ is used to compose two 'liftControl' operations:+the outer provided by a 'MonadTransControl' instance,+and the inner provided as the argument.++It satisfies @'liftLiftControlBase' 'idLiftControl' == 'liftControl'@.++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+@++using the 'MonadTransControl' instance of @'StateT' s@.++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@:++@+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 a) → m a) -- ^ @liftControlBase@ operation → ((RunInBase (t m) base → base a) → t m a)-liftLiftControlBase lftCtrlBase = \f → liftControl $ \run →+liftLiftControlBase lftCtrlBase = \f → liftControl $ \run1 → lftCtrlBase $ \runInBase →- f $ liftM (join ∘ lift) ∘ runInBase ∘ run+ let run = liftM (join ∘ lift) ∘ runInBase ∘ run1+ in f run -- The End ---------------------------------------------------------------------
monad-control.cabal view
@@ -1,5 +1,5 @@ Name: monad-control-Version: 0.1+Version: 0.2 Synopsis: Lift control operations, like exception catching, through monad transformers Description: This package defines the type class @MonadControlIO@, a subset of@@ -18,8 +18,8 @@ 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 about- 2 times faster than @monad-peel@:+ The following @critertion@ based benchmark shows that @monad-control@+ is on average about 2.5 times faster than @monad-peel@: . <http://code.haskell.org/~basvandijk/code/bench-monad-peel-control>