Hello community, here is the log from the commit of package ghc-monad-control for openSUSE:Factory checked in at 2015-05-21 08:12:59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ghc-monad-control (Old) and /work/SRC/openSUSE:Factory/.ghc-monad-control.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-monad-control" Changes: -------- --- /work/SRC/openSUSE:Factory/ghc-monad-control/ghc-monad-control.changes 2014-04-02 17:19:08.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.ghc-monad-control.new/ghc-monad-control.changes 2015-05-21 08:12:59.000000000 +0200 @@ -1,0 +2,19 @@ +Tue Apr 21 19:32:20 UTC 2015 - [email protected] + +- update to 1.0.0.4 + +* Support transformers-compat-0.4.*. +* Unconditionally add ExceptT instances using transformers-compat. + Courtesy of Adam Bergmark. +* Add a base >= 4.5 constraint because monad-control only builds on GHC >= 7.4. +* Use Safe instead of Trustworthy. + This requires a dependency on stm. +* Switch the associated data types StT and StM to associated type synonyms. + This is an API breaking change. To fix your MonadTransControl or + MonadBaseControl instances simply remove the StT or StM constructors + and deconstructors for your monad transformers or monad. +* Add the embed, embed_ and liftBaseOpDiscard functions. +* Support transformers-0.4.0.0 +* Drop unicode syntax and symbols + +------------------------------------------------------------------- Old: ---- monad-control-0.3.2.1.tar.gz New: ---- monad-control-1.0.0.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ghc-monad-control.spec ++++++ --- /var/tmp/diff_new_pack.u8qCqQ/_old 2015-05-21 08:13:00.000000000 +0200 +++ /var/tmp/diff_new_pack.u8qCqQ/_new 2015-05-21 08:13:00.000000000 +0200 @@ -1,7 +1,7 @@ # # spec file for package ghc-monad-control # -# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,22 +18,23 @@ %global pkg_name monad-control -Name: ghc-monad-control -Version: 0.3.2.1 +Name: ghc-%{pkg_name} +Version: 1.0.0.4 Release: 0 Summary: Lift control operations, like exception catching, through monad transformers License: BSD-3-Clause Group: System/Libraries -Url: http://hackage.haskell.org/package/%{pkg_name} -Source0: http://hackage.haskell.org/packages/archive/%{pkg_name}/%{version}/%{pkg_name}-%{version}.tar.gz +Url: https://hackage.haskell.org/package/%{pkg_name} +Source0: https://hackage.haskell.org/package/%{pkg_name}-%{version}/%{pkg_name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: ghc-Cabal-devel BuildRequires: ghc-rpm-macros # Begin cabal-rpm deps: -BuildRequires: ghc-base-unicode-symbols-devel +BuildRequires: ghc-stm-devel BuildRequires: ghc-transformers-base-devel +BuildRequires: ghc-transformers-compat-devel BuildRequires: ghc-transformers-devel # End cabal-rpm deps @@ -53,18 +54,14 @@ exploits the 'RankNTypes' and 'TypeFamilies' language extensions to simplify and speedup most definitions. -The following 'criterion' 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. - %package devel Summary: Haskell %{pkg_name} library development files Group: Development/Libraries/Other -Provides: %{name}-static = %{version}-%{release} -Requires: %{name} = %{version}-%{release} Requires: ghc-compiler = %{ghc_version} +Requires(post): ghc-compiler = %{ghc_version} +Requires(postun): ghc-compiler = %{ghc_version} +Requires: %{name} = %{version}-%{release} %description devel This package provides the Haskell %{pkg_name} library development files. ++++++ monad-control-0.3.2.1.tar.gz -> monad-control-1.0.0.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/monad-control-0.3.2.1/CHANGELOG new/monad-control-1.0.0.4/CHANGELOG --- old/monad-control-0.3.2.1/CHANGELOG 1970-01-01 01:00:00.000000000 +0100 +++ new/monad-control-1.0.0.4/CHANGELOG 2015-02-13 20:55:40.000000000 +0100 @@ -0,0 +1,444 @@ +1.0.0.4 + +* Support transformers-compat-0.4.*. + + +1.0.0.3 + +* Unconditionally add ExceptT instances using transformers-compat. + Courtesy of Adam Bergmark. + + +1.0.0.2 + +* Add a base >= 4.5 constraint because monad-control only builds on GHC >= 7.4. + + +1.0.0.1 + +* Use Safe instead of Trustworthy. + + This requires a dependency on stm. + + +1.0.0.0 + +* Switch the associated data types StT and StM to associated type synonyms. + + This is an API breaking change. To fix your MonadTransControl or + MonadBaseControl instances simply remove the StT or StM constructors + and deconstructors for your monad transformers or monad. + +* Add the embed, embed_ and liftBaseOpDiscard functions. + + +0.3.3.0 + +* Support transformers-0.4.0.0 + +* Drop unicode syntax and symbols + + +0.3.2.3 + +* Fix haddock documentation error + + +0.3.2.2 + +* Fix preprocessor directive for GHC 7.6.3 + + +0.3.2.1 + +* Resolve #14. Bump upper version bound of base to 5 + + +0.3.2 + +* Added defaultLiftWith and defaultRestoreT to simplify defining + MonadTransControl for newtypes. + + +0.3.1.4 + +* Compatibility with ghc head + + +0.3.1.3 + +* Added a Trustworthy flag + + +0.3.1.2 + +* Fix issue #9. Replace all Unicode in type variables. + + +0.3.1.1 + +* Add MonadBaseControl instances for ST and STM. + + +0.3 + +(Released on: Fri Dec 2 09:52:16 UTC 2011) + +* Major new API which IMHO is easier to understand than the old one. + +* On average about 60 times faster than the previous release! + +* New package lifted-base providing lifted versions of functions from the base + library. It exports the following modules: + + - Control.Exception.Lifted + - Control.Concurrent.Lifted + - Control.Concurrent.MVar.Lifted + - System.Timeout.Lifted + + Not all modules from base are converted yet. If you need a lifted version of + some function from base, just ask me to add it or send me a patch. + + +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) + +* Switched to git on github. + +* Tested with base-4.4 and ghc-7.2.1. + +* Use the new cabal test-suite feature. + + +0.2.0.1 + +(Released on: Wed Mar 16 15:53:50 UTC 2011) + +* Added laws for MonadTransControl and MonadControlIO + +* Bug fix: Add proper laziness to the MonadTransControl instances + of the lazy StateT, WriteT and RWST + These all failed the law: control $ \run -> run t = t + where t = return undefined + +* Add INLINABLE pragmas for most public functions + A simple benchmark showed some functions + (bracket and mask) improving by 30%. + + +0.2 + +(Released on: Wed Feb 9 12:05:26 UTC 2011) + +* Use RunInBase in the type of idLiftControl. + +* Added this NEWS file. + +* Only parameterize Run with t and use RankNTypes to quantify n and o + -liftControl :: (Monad m, Monad n, Monad o) => (Run t n o -> m a) -> t m a + +liftControl :: Monad m => (Run t -> m a) -> t m a + + -type Run t n o = forall b. t n b -> n (t o b) + +type Run t = forall n o b. (Monad n, Monad o, Monad (t o)) => t n b -> n (t o b) + + Bumped version from 0.1 to 0.2 to indicate this breaking change in API. + +* Added example of a derivation of liftControlIO. + Really enlightening! + + +0.1 + +(Released on: Sat Feb 5 23:36:21 UTC 2011) + +* Initial release + +This is the announcement message sent to the Haskell mailinglists: +http://www.mail-archive.com/[email protected]/msg23278.html + + +Dear all, + +Several attempts have been made to lift control operations (functions +that use monadic actions as input instead of just output) through +monad transformers: + +MonadCatchIO-transformers[1] provided a type class that allowed to +overload some often used control operations (catch, block and +unblock). Unfortunately that library was limited to those operations. +It was not possible to use, say, alloca in a monad transformer. More +importantly however, the library was broken as was explained[2] by +Michael Snoyman. In response Michael created the MonadInvertIO type +class which solved the problems. Then Anders Kaseorg created the +monad-peel library which provided an even nicer implementation. + +monad-control is a rewrite of monad-peel that uses CPS style +operations and exploits the RankNTypes language extension to simplify +and speedup most functions. A very preliminary and not yet fully +representative, benchmark shows that monad-control is on average about +2.6 times faster than monad-peel: + +bracket: 2.4 x faster +bracket_: 3.1 x faster +catch: 1.8 x faster +try: 4.0 x faster +mask: 2.0 x faster + +Note that, although the package comes with a test suite that passes, I +still consider it highly experimental. + + +API DOCS: + +http://hackage.haskell.org/package/monad-control + + +INSTALLING: + +$ cabal update +$ cabal install monad-control + + +TESTING: + +The package contains a copy of the monad-peel test suite written by +Anders. You can perform the tests using: + +$ cabal unpack monad-control +$ cd monad-control +$ cabal configure -ftest +$ cabal test + + +BENCHMARKING: + +$ darcs get http://bifunctor.homelinux.net/~bas/bench-monad-peel-control/ +$ cd bench-monad-peel-control +$ cabal configure +$ cabal build +$ dist/build/bench-monad-peel-control/bench-monad-peel-control + + +DEVELOPING: + +The darcs repository will be hosted on code.haskell.org ones that +server is back online. For the time being you can get the repository +from: + +$ darcs get http://bifunctor.homelinux.net/~bas/monad-control/ + + +TUTORIAL: + +This short unpolished tutorial will explain how to lift control +operations through monad transformers. Our goal is to lift a control +operation like: + +foo ∷ M a → M a + +where M is some monad, into a transformed monad like 'StateT M': + +foo' ∷ StateT M a → StateT M a + +The first thing we need to do is write an instance for the +MonadTransControl type class: + +class MonadTrans t ⇒ MonadTransControl t where + liftControl ∷ (Monad m, Monad n, Monad o) + ⇒ (Run t n o → m a) → t m a + +If you ignore the Run argument for now, you'll see that liftControl is +identical to the 'lift' method of the MonadTrans type class: + +class MonadTrans t where + lift ∷ Monad m ⇒ m a → t m a + +So the instance for MonadTransControl will probably look very much +like the instance for MonadTrans. Let's see: + +instance MonadTransControl (StateT s) where + liftControl f = StateT $ \s → liftM (\x → (x, s)) (f run) + +So what is this run function? Let's look at its type: + +type Run t n o = ∀ b. t n b → n (t o b) + +The run function executes a transformed monadic action 't n b' in the +non-transformed monad 'n'. In our case the 't' will be a StateT +computation. The only way to run a StateT computation is to give it +some state and the only state we have lying around is the one from the +outer computation: 's'. So let's run it on 's': + +instance MonadTransControl (StateT s) where + liftControl f = + StateT $ \s → + let run t = ... runStateT t s ... + in liftM (\x → (x, s)) (f run) + +Now that we are able to run a transformed monadic action, we're almost +done. Look at the type of Run again. The function should leave the +result 't o b' in the monad 'n'. This 't o b' computation should +contain the final state after running the supplied 't n b' +computation. In case of our StateT it should contain the final state +s': + +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) + +This final computation, "StateT $ \_ → return (x, s')", can later be +used to restore the final state. Now that we have our +MonadTransControl instance we can start using it. Recall that our goal +was to lift "foo ∷ M a → M a" into our StateT transformer yielding the +function "foo' ∷ StateT M a → StateT M a". + +To define foo', the first thing we need to do is call liftControl: + +foo' t = liftControl $ \run → ... + +This captures the current state of the StateT computation and provides +us with the run function that allows us to run a StateT computation on +this captured state. + +Now recall the type of liftControl ∷ (Run t n o → m a) → t m a. You +can see that in place of the ... we must fill in a value of type 'm +a'. In our case this will be a value of type 'M a'. We can construct +such a value by calling foo. However, foo expects an argument of type +'M a'. Fortunately we can provide one if we convert the supplied 't' +computation of type 'StateT M a' to 'M a' using our run function of +type ∀ b. StateT M b → M (StateT o b): + +foo' t = ... liftControl $ \run → foo $ run t + +However, note that the run function returns the final StateT +computation inside M. So the type of the right hand side is now +'StateT M (StateT o b)'. We would like to restore this final state. We +can do that using join: + +foo' t = join $ liftControl $ \run → foo $ run t + +That's it! Note that because it's so common to join after a +liftControl I provide an abstraction for it: + +control = join ∘ liftControl + +Allowing you to simplify foo' to: + +foo' t = control $ \run → foo $ run t + +Probably the most common control operations that you want to lift +through your transformers are IO operations. Think about: bracket, +alloca, mask, etc.. For this reason I provide the MonadControlIO type +class: + +class MonadIO m ⇒ MonadControlIO m where + liftControlIO ∷ (RunInBase m IO → IO a) → m a + +Again, if you ignore the RunInBase argument, you will see that +liftControlIO is identical to the liftIO method of the MonadIO type +class: + +class Monad m ⇒ MonadIO m where + liftIO ∷ IO a → m a + +Just like Run, RunInBase allows you to run your monadic computation +inside your base monad, which in case of liftControlIO is IO: + +type RunInBase m base = ∀ b. m b → base (m b) + +The instance for the base monad is trivial: + +instance MonadControlIO IO where + liftControlIO = idLiftControl + +idLiftControl directly executes f and passes it a run function which +executes the given action and lifts the result r into the trivial +'return r' action: + +idLiftControl ∷ Monad m ⇒ ((∀ b. m b → m (m b)) → m a) → m a +idLiftControl f = f $ liftM $ \r -> return r + +The instances for the transformers are all identical. Let's look at +StateT and ReaderT: + +instance MonadControlIO m ⇒ MonadControlIO (StateT s m) where + liftControlIO = liftLiftControlBase liftControlIO + +instance MonadControlIO m ⇒ MonadControlIO (ReaderT r m) where + liftControlIO = liftLiftControlBase liftControlIO + +The magic function is liftLiftControlBase. This function is used to +compose two liftControl operations, the outer provided by a +MonadTransControl instance and the inner provided as the argument: + +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) +liftLiftControlBase lftCtrlBase = + \f → liftControl $ \run → + lftCtrlBase $ \runInBase → + f $ liftM (join ∘ lift) ∘ runInBase ∘ run + +Basically it captures the state of the outer monad transformer using +liftControl. Then it captures the state of the inner monad using the +supplied lftCtrlBase function. If you recall the identical definitions +of the liftControlIO methods: 'liftLiftControlBase liftControlIO' you +will see that this lftCtrlBase function is the recursive step of +liftLiftControlBase. If you use 'liftLiftControlBase liftControlIO' in +a stack of monad transformers a chain of liftControl operations is +created: + +liftControl $ \run1 -> liftControl $ \run2 -> liftControl $ \run3 -> ... + +This will recurse until we hit the base monad. Then +liftLiftControlBase will finally run f in the base monad supplying it +with a run function that is able to run a 't m a' computation in the +base monad. It does this by composing the run and runInBase functions. +Note that runInBase is basically the composition: '... ∘ run3 ∘ run2'. + +However, just composing the run and runInBase functions is not enough. +Namely: runInBase ∘ run ∷ ∀ b. t m b → base (m (t m b)) while we need +to have ∀ b. t m b → base (t m b). So we need to lift the 'm (t m b)' +computation inside t yielding: 't m (t m b)' and then join that to get +'t m b'. + +Now that we have our MonadControlIO instances we can start using them. +Let's look at how to lift 'bracket' into a monad supporting +MonadControlIO. Before we do that I define a little convenience +function similar to 'control': + +controlIO = join ∘ liftControlIO + +Bracket just calls controlIO which captures the state of m and +provides us with a runInIO function which allows us to run an m +computation in IO: + +bracket ∷ MonadControlIO m + ⇒ m a → (a → m b) → (a → m c) → m c +bracket before after thing = + controlIO $ \runInIO → + E.bracket (runInIO before) + (\m → runInIO $ m >>= after) + (\m → runInIO $ m >>= thing) + +I welcome any comments, questions or patches. + +Regards, + +Bas + +[1] http://hackage.haskell.org/package/MonadCatchIO-transformers +[2] http://docs.yesodweb.com/blog/invertible-monads-exceptions-allocations/ +[3] http://hackage.haskell.org/package/monad-peel diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/monad-control-0.3.2.1/Control/Monad/Trans/Control.hs new/monad-control-1.0.0.4/Control/Monad/Trans/Control.hs --- old/monad-control-0.3.2.1/Control/Monad/Trans/Control.hs 2013-04-23 18:40:21.000000000 +0200 +++ new/monad-control-1.0.0.4/Control/Monad/Trans/Control.hs 2015-02-13 20:55:40.000000000 +0100 @@ -1,16 +1,19 @@ {-# LANGUAGE CPP - , UnicodeSyntax , NoImplicitPrelude , RankNTypes , TypeFamilies , FunctionalDependencies , FlexibleInstances , UndecidableInstances - , MultiParamTypeClasses - #-} + , MultiParamTypeClasses #-} #if __GLASGOW_HASKELL__ >= 702 -{-# LANGUAGE Trustworthy #-} +{-# LANGUAGE Safe #-} +#endif + +#if MIN_VERSION_transformers(0,4,0) +-- Hide warnings for the deprecated ErrorT transformer: +{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-} #endif {- | @@ -20,13 +23,6 @@ Maintainer : Bas van Dijk <[email protected]> Stability : experimental - -(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 @@ -35,21 +31,21 @@ -- ** Defaults for MonadTransControl -- $MonadTransControlDefaults - , defaultLiftWith, defaultRestoreT + , RunDefault, defaultLiftWith, defaultRestoreT -- * MonadBaseControl , MonadBaseControl (..), RunInBase -- ** Defaults for MonadBaseControl -- $MonadBaseControlDefaults - , ComposeSt, defaultLiftBaseWith, defaultRestoreM + , ComposeSt, RunInBaseDefault, defaultLiftBaseWith, defaultRestoreM -- * Utility functions - , control + , control, embed, embed_ , liftBaseOp, liftBaseOp_ - , liftBaseDiscard + , liftBaseDiscard, liftBaseOpDiscard ) where @@ -58,24 +54,20 @@ -------------------------------------------------------------------------------- -- from base: -import Data.Function ( ($), const ) +import Data.Function ( (.), ($), const ) import Data.Monoid ( Monoid, mempty ) import Control.Monad ( Monad, (>>=), return, liftM ) import System.IO ( IO ) import Data.Maybe ( Maybe ) import Data.Either ( Either ) -#if MIN_VERSION_base(4,3,0) -import GHC.Conc.Sync ( STM ) +#if MIN_VERSION_base(4,4,0) +import Control.Monad.ST.Lazy.Safe ( ST ) +import qualified Control.Monad.ST.Safe as Strict ( ST ) #endif -#if MIN_VERSION_base(4,4,0) || defined(INSTANCE_ST) -import Control.Monad.ST.Lazy ( ST ) -import qualified Control.Monad.ST.Strict as Strict ( ST ) -#endif - --- from base-unicode-symbols: -import Data.Function.Unicode ( (∘) ) +-- from stm: +import Control.Monad.STM ( STM ) -- from transformers: import Control.Monad.Trans.Class ( MonadTrans ) @@ -88,6 +80,7 @@ import Control.Monad.Trans.State ( StateT (StateT), runStateT ) import Control.Monad.Trans.Writer ( WriterT (WriterT), runWriterT ) import Control.Monad.Trans.RWS ( RWST (RWST), runRWST ) +import Control.Monad.Trans.Except ( ExceptT (ExceptT), runExceptT ) import qualified Control.Monad.Trans.RWS.Strict as Strict ( RWST (RWST), runRWST ) import qualified Control.Monad.Trans.State.Strict as Strict ( StateT (StateT), runStateT ) @@ -102,17 +95,19 @@ import Control.Monad ( void ) #else import Data.Functor (Functor, fmap) -void ∷ Functor f ⇒ f a → f () +void :: Functor f => f a -> f () void = fmap (const ()) #endif +import Prelude (id) + -------------------------------------------------------------------------------- -- MonadTransControl type class -------------------------------------------------------------------------------- -class MonadTrans t ⇒ MonadTransControl t where +class MonadTrans t => MonadTransControl t where -- | Monadic state of @t@. - data StT t ∷ * → * + type StT t a :: * -- | @liftWith@ is similar to 'lift' in that it lifts a computation from -- the argument monad to the constructed monad. @@ -127,7 +122,7 @@ -- @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 a) → t m a + liftWith :: Monad m => (Run t -> m a) -> t m a -- | Construct a @t@ computation from the monadic state of @t@ that is -- returned from a 'Run' function. @@ -135,7 +130,7 @@ -- Instances should satisfy: -- -- @liftWith (\\run -> run t) >>= restoreT . return = t@ - restoreT ∷ Monad m ⇒ m (StT t a) → t m a + restoreT :: Monad m => m (StT t a) -> t m a -- | A function that runs a transformed monad @t n@ on the monadic state that -- was captured by 'liftWith' @@ -143,7 +138,7 @@ -- 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 b. Monad n ⇒ t n b → n (StT t b) +type Run t = forall n b. Monad n => t n b -> n (StT t b) -------------------------------------------------------------------------------- @@ -151,37 +146,43 @@ -------------------------------------------------------------------------------- -- $MonadTransControlDefaults --- Following functions can be used to define 'MonadTransControl' instances for --- newtypes. -- --- @{-\# LANGUAGE GeneralizedNewtypeDeriving \#-} +-- The following functions can be used to define a 'MonadTransControl' instance +-- for a monad transformer which simply wraps another monad transformer which +-- already has a @MonadTransControl@ instance. For example: +-- +-- @ +-- {-\# LANGUAGE GeneralizedNewtypeDeriving \#-} -- -- newtype CounterT m a = CounterT {unCounterT :: StateT Int m a} -- deriving (Monad, MonadTrans) -- -- instance MonadTransControl CounterT where --- newtype StT CounterT a = StCounter {unStCounter :: StT (StateT Int) a} --- liftWith = 'defaultLiftWith' CounterT unCounterT StCounter --- restoreT = 'defaultRestoreT' CounterT unStCounter +-- type StT CounterT a = StT (StateT Int) a +-- liftWith = 'defaultLiftWith' CounterT unCounterT +-- restoreT = 'defaultRestoreT' CounterT -- @ +-- | A function like 'Run' that runs a monad transformer @t@ which wraps the +-- monad transformer @t'@. This is used in 'defaultLiftWith'. +type RunDefault t t' = forall n b. Monad n => t n b -> n (StT t' b) + -- | Default definition for the 'liftWith' method. -defaultLiftWith ∷ (Monad m, MonadTransControl n) - ⇒ (∀ b. n m b → t m b) -- ^ Monad constructor - → (∀ o b. t o b → n o b) -- ^ Monad deconstructor - → (∀ b. StT n b → StT t b) -- ^ 'StT' constructor - → (Run t → m a) - → t m a -defaultLiftWith t unT stT = \f → t $ liftWith $ \run → f $ liftM stT ∘ run ∘ unT -{-# INLINE defaultLiftWith #-} - -defaultRestoreT ∷ (Monad m, MonadTransControl n) - ⇒ (n m a → t m a) -- ^ Monad constructor - → (StT t a → StT n a) -- ^ 'StT' deconstructor - → m (StT t a) - → t m a -defaultRestoreT t unStT = t ∘ restoreT ∘ liftM unStT -{-# INLINE defaultRestoreT #-} +defaultLiftWith :: (Monad m, MonadTransControl n) + => (forall b. n m b -> t m b) -- ^ Monad constructor + -> (forall o b. t o b -> n o b) -- ^ Monad deconstructor + -> (RunDefault t n -> m a) + -> t m a +defaultLiftWith t unT = \f -> t $ liftWith $ \run -> f $ run . unT +{-# INLINABLE defaultLiftWith #-} + +-- | Default definition for the 'restoreT' method. +defaultRestoreT :: (Monad m, MonadTransControl n) + => (n m a -> t m a) -- ^ Monad constructor + -> m (StT n a) + -> t m a +defaultRestoreT t = t . restoreT +{-# INLINABLE defaultRestoreT #-} -------------------------------------------------------------------------------- @@ -189,99 +190,106 @@ -------------------------------------------------------------------------------- instance MonadTransControl IdentityT where - newtype StT IdentityT a = StId {unStId ∷ a} - liftWith f = IdentityT $ f $ liftM StId ∘ runIdentityT - restoreT = IdentityT ∘ liftM unStId - {-# INLINE liftWith #-} - {-# INLINE restoreT #-} + type StT IdentityT a = a + liftWith f = IdentityT $ f $ runIdentityT + restoreT = IdentityT + {-# INLINABLE liftWith #-} + {-# INLINABLE restoreT #-} instance MonadTransControl MaybeT where - newtype StT MaybeT a = StMaybe {unStMaybe ∷ Maybe a} - liftWith f = MaybeT $ liftM return $ f $ liftM StMaybe ∘ runMaybeT - restoreT = MaybeT ∘ liftM unStMaybe - {-# INLINE liftWith #-} - {-# INLINE restoreT #-} - -instance Error e ⇒ MonadTransControl (ErrorT e) where - newtype StT (ErrorT e) a = StError {unStError ∷ Either e a} - liftWith f = ErrorT $ liftM return $ f $ liftM StError ∘ runErrorT - restoreT = ErrorT ∘ liftM unStError - {-# INLINE liftWith #-} - {-# INLINE restoreT #-} + type StT MaybeT a = Maybe a + liftWith f = MaybeT $ liftM return $ f $ runMaybeT + restoreT = MaybeT + {-# INLINABLE liftWith #-} + {-# INLINABLE restoreT #-} + +instance Error e => MonadTransControl (ErrorT e) where + type StT (ErrorT e) a = Either e a + liftWith f = ErrorT $ liftM return $ f $ runErrorT + restoreT = ErrorT + {-# INLINABLE liftWith #-} + {-# INLINABLE restoreT #-} + +instance MonadTransControl (ExceptT e) where + type StT (ExceptT e) a = Either e a + liftWith f = ExceptT $ liftM return $ f $ runExceptT + restoreT = ExceptT + {-# INLINABLE liftWith #-} + {-# INLINABLE restoreT #-} instance MonadTransControl ListT where - newtype StT ListT a = StList {unStList ∷ [a]} - liftWith f = ListT $ liftM return $ f $ liftM StList ∘ runListT - restoreT = ListT ∘ liftM unStList - {-# INLINE liftWith #-} - {-# INLINE restoreT #-} + type StT ListT a = [a] + liftWith f = ListT $ liftM return $ f $ runListT + restoreT = ListT + {-# INLINABLE liftWith #-} + {-# INLINABLE restoreT #-} instance MonadTransControl (ReaderT r) where - newtype StT (ReaderT r) a = StReader {unStReader ∷ a} - liftWith f = ReaderT $ \r → f $ \t → liftM StReader $ runReaderT t r - restoreT = ReaderT ∘ const ∘ liftM unStReader - {-# INLINE liftWith #-} - {-# INLINE restoreT #-} + type StT (ReaderT r) a = a + liftWith f = ReaderT $ \r -> f $ \t -> runReaderT t r + restoreT = ReaderT . const + {-# INLINABLE liftWith #-} + {-# INLINABLE restoreT #-} instance MonadTransControl (StateT s) where - newtype StT (StateT s) a = StState {unStState ∷ (a, 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 #-} + type StT (StateT s) a = (a, s) + liftWith f = StateT $ \s -> + liftM (\x -> (x, s)) + (f $ \t -> runStateT t s) + restoreT = StateT . const + {-# INLINABLE liftWith #-} + {-# INLINABLE restoreT #-} instance MonadTransControl (Strict.StateT s) where - newtype StT (Strict.StateT s) a = StState' {unStState' ∷ (a, 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 - newtype StT (WriterT w) a = StWriter {unStWriter ∷ (a, 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 - newtype StT (Strict.WriterT w) a = StWriter' {unStWriter' ∷ (a, 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 - newtype StT (RWST r w s) a = StRWS {unStRWS ∷ (a, 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 #-} + type StT (Strict.StateT s) a = (a, s) + liftWith f = Strict.StateT $ \s -> + liftM (\x -> (x, s)) + (f $ \t -> Strict.runStateT t s) + restoreT = Strict.StateT . const + {-# INLINABLE liftWith #-} + {-# INLINABLE restoreT #-} + +instance Monoid w => MonadTransControl (WriterT w) where + type StT (WriterT w) a = (a, w) + liftWith f = WriterT $ liftM (\x -> (x, mempty)) + (f $ runWriterT) + restoreT = WriterT + {-# INLINABLE liftWith #-} + {-# INLINABLE restoreT #-} + +instance Monoid w => MonadTransControl (Strict.WriterT w) where + type StT (Strict.WriterT w) a = (a, w) + liftWith f = Strict.WriterT $ liftM (\x -> (x, mempty)) + (f $ Strict.runWriterT) + restoreT = Strict.WriterT + {-# INLINABLE liftWith #-} + {-# INLINABLE restoreT #-} + +instance Monoid w => MonadTransControl (RWST r w s) where + type StT (RWST r w s) a = (a, s, w) + liftWith f = RWST $ \r s -> liftM (\x -> (x, s, mempty)) + (f $ \t -> runRWST t r s) + restoreT mSt = RWST $ \_ _ -> mSt + {-# INLINABLE liftWith #-} + {-# INLINABLE restoreT #-} -instance Monoid w ⇒ MonadTransControl (Strict.RWST r w s) where - newtype StT (Strict.RWST r w s) a = StRWS' {unStRWS' ∷ (a, s, w)} +instance Monoid w => MonadTransControl (Strict.RWST r w s) where + type StT (Strict.RWST r w s) a = (a, 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 #-} + Strict.RWST $ \r s -> liftM (\x -> (x, s, mempty)) + (f $ \t -> Strict.runRWST t r s) + restoreT mSt = Strict.RWST $ \_ _ -> mSt + {-# INLINABLE liftWith #-} + {-# INLINABLE restoreT #-} -------------------------------------------------------------------------------- -- MonadBaseControl type class -------------------------------------------------------------------------------- -class MonadBase b m ⇒ MonadBaseControl b m | m → b where +class MonadBase b m => MonadBaseControl b m | m -> b where -- | Monadic state of @m@. - data StM m ∷ * → * + type StM m a :: * -- | @liftBaseWith@ is similar to 'liftIO' and 'liftBase' in that it -- lifts a base computation to the constructed monad. @@ -296,7 +304,7 @@ -- @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 a) → m a + liftBaseWith :: (RunInBase m b -> b a) -> m a -- | Construct a @m@ computation from the monadic state of @m@ that is -- returned from a 'RunInBase' function. @@ -304,7 +312,7 @@ -- Instances should satisfy: -- -- @liftBaseWith (\\runInBase -> runInBase m) >>= restoreM = m@ - restoreM ∷ StM m a → m a + restoreM :: StM m a -> m a -- | A function that runs a @m@ computation on the monadic state that was -- captured by 'liftBaseWith' @@ -312,35 +320,33 @@ -- 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 = ∀ a. m a → b (StM m a) +type RunInBase m b = forall a. m a -> b (StM m a) -------------------------------------------------------------------------------- -- MonadBaseControl instances for all monads in the base library -------------------------------------------------------------------------------- -#define BASE(M, ST) \ +#define BASE(M) \ instance MonadBaseControl (M) (M) where { \ - newtype StM (M) a = ST a; \ - liftBaseWith f = f $ liftM ST; \ - restoreM (ST x) = return x; \ - {-# INLINE liftBaseWith #-}; \ - {-# INLINE restoreM #-}} - -BASE(IO, StIO) -BASE(Maybe, St) -BASE(Either e, StE) -BASE([], StL) -BASE((→) r, StF) -BASE(Identity, StI) - -#if MIN_VERSION_base(4,3,0) -BASE(STM, StSTM) -#endif - -#if MIN_VERSION_base(4,4,0) || defined(INSTANCE_ST) -BASE(Strict.ST s, StSTS) -BASE( ST s, StST) + type StM (M) a = a; \ + liftBaseWith f = f id; \ + restoreM = return; \ + {-# INLINABLE liftBaseWith #-}; \ + {-# INLINABLE restoreM #-}} + +BASE(IO) +BASE(Maybe) +BASE(Either e) +BASE([]) +BASE((->) r) +BASE(Identity) + +BASE(STM) + +#if MIN_VERSION_base(4,4,0) +BASE(Strict.ST s) +BASE( ST s) #endif #undef BASE @@ -357,18 +363,18 @@ -- -- @ -- 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 +-- type StM (T m) a = 'ComposeSt' T m a +-- liftBaseWith = 'defaultLiftBaseWith' +-- restoreM = 'defaultRestoreM' -- @ -- -- 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 +-- type StM B a = a +-- liftBaseWith f = f 'id' +-- restoreM = 'return' -- @ -- | Handy type synonym that composes the monadic states of @t@ and @m@. @@ -376,62 +382,65 @@ -- It can be used to define the 'StM' for new 'MonadBaseControl' instances. type ComposeSt t m a = StM m (StT t a) +-- | A function like 'RunInBase' that runs a monad transformer @t@ in its base +-- monad @b@. It is used in 'defaultLiftBaseWith'. +type RunInBaseDefault t m b = forall a. t m a -> b (ComposeSt t m a) + -- | 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 = \\f -> 'liftWith' $ \\run -> +-- 'liftBaseWith' $ \\runInBase -> +-- f $ runInBase . run -- @ -defaultLiftBaseWith ∷ (MonadTransControl t, MonadBaseControl b m) - ⇒ (∀ c. ComposeSt t m c → StM (t m) c) -- ^ 'StM' constructor - → ((RunInBase (t m) b → b a) → t m a) -defaultLiftBaseWith stM = \f → liftWith $ \run → - liftBaseWith $ \runInBase → - f $ liftM stM ∘ runInBase ∘ run -{-# INLINE defaultLiftBaseWith #-} +defaultLiftBaseWith :: (MonadTransControl t, MonadBaseControl b m) + => (RunInBaseDefault t m b -> b a) -> t m a +defaultLiftBaseWith = \f -> liftWith $ \run -> + liftBaseWith $ \runInBase -> + f $ runInBase . run +{-# INLINABLE defaultLiftBaseWith #-} -- | Default definition for the 'restoreM' method. -- --- Note that: @defaultRestoreM unStM = 'restoreT' . 'restoreM' . unStM@ -defaultRestoreM ∷ (MonadTransControl t, MonadBaseControl b m) - ⇒ (StM (t m) a → ComposeSt t m a) -- ^ 'StM' deconstructor - → (StM (t m) a → t m a) -defaultRestoreM unStM = restoreT ∘ restoreM ∘ unStM -{-# INLINE defaultRestoreM #-} +-- Note that: @defaultRestoreM = 'restoreT' . 'restoreM'@ +defaultRestoreM :: (MonadTransControl t, MonadBaseControl b m) + => ComposeSt t m a -> t m a +defaultRestoreM = restoreT . restoreM +{-# INLINABLE defaultRestoreM #-} -------------------------------------------------------------------------------- -- MonadBaseControl transformer instances -------------------------------------------------------------------------------- -#define BODY(T, ST, unST) { \ - newtype StM (T m) a = ST {unST ∷ ComposeSt (T) m a}; \ - 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) +#define BODY(T) { \ + type StM (T m) a = ComposeSt (T) m a; \ + liftBaseWith = defaultLiftBaseWith; \ + restoreM = defaultRestoreM; \ + {-# INLINABLE liftBaseWith #-}; \ + {-# INLINABLE restoreM #-}} + +#define TRANS( T) \ + instance ( MonadBaseControl b m) => MonadBaseControl b (T m) where BODY(T) +#define TRANS_CTX(CTX, T) \ + instance (CTX, MonadBaseControl b m) => MonadBaseControl b (T m) where BODY(T) + +TRANS(IdentityT) +TRANS(MaybeT) +TRANS(ListT) +TRANS(ReaderT r) +TRANS(Strict.StateT s) +TRANS( StateT s) +TRANS(ExceptT e) + +TRANS_CTX(Error e, ErrorT e) +TRANS_CTX(Monoid w, Strict.WriterT w) +TRANS_CTX(Monoid w, WriterT w) +TRANS_CTX(Monoid w, Strict.RWST r w s) +TRANS_CTX(Monoid w, RWST r w s) -------------------------------------------------------------------------------- @@ -439,9 +448,21 @@ -------------------------------------------------------------------------------- -- | An often used composition: @control f = 'liftBaseWith' f >>= 'restoreM'@ -control ∷ MonadBaseControl b m ⇒ (RunInBase m b → b (StM m a)) → m a +control :: MonadBaseControl b m => (RunInBase m b -> b (StM m a)) -> m a control f = liftBaseWith f >>= restoreM -{-# INLINE control #-} +{-# INLINABLE control #-} + +-- | Embed a transformer function as an function in the base monad returning a +-- mutated transformer state. +embed :: MonadBaseControl b m => (a -> m c) -> m (a -> b (StM m c)) +embed f = liftBaseWith $ \runInBase -> return (runInBase . f) +{-# INLINABLE embed #-} + +-- | Performs the same function as 'embed', but discards transformer state +-- from the embedded function. +embed_ :: MonadBaseControl b m => (a -> m ()) -> m (a -> b ()) +embed_ f = liftBaseWith $ \runInBase -> return (void . runInBase . f) +{-# INLINABLE embed_ #-} -- | @liftBaseOp@ is a particular application of 'liftBaseWith' that allows -- lifting control operations of type: @@ -451,11 +472,11 @@ -- For example: -- -- @liftBaseOp alloca :: 'MonadBaseControl' 'IO' m => (Ptr a -> m c) -> m c@ -liftBaseOp ∷ MonadBaseControl b m - ⇒ ((a → b (StM m c)) → b (StM m d)) - → ((a → m c) → m d) -liftBaseOp f = \g → control $ \runInBase → f $ runInBase ∘ g -{-# INLINE liftBaseOp #-} +liftBaseOp :: MonadBaseControl b m + => ((a -> b (StM m c)) -> b (StM m d)) + -> ((a -> m c) -> m d) +liftBaseOp f = \g -> control $ \runInBase -> f $ runInBase . g +{-# INLINABLE liftBaseOp #-} -- | @liftBaseOp_@ is a particular application of 'liftBaseWith' that allows -- lifting control operations of type: @@ -465,11 +486,11 @@ -- For example: -- -- @liftBaseOp_ mask_ :: 'MonadBaseControl' 'IO' m => m a -> m a@ -liftBaseOp_ ∷ MonadBaseControl b m - ⇒ (b (StM m a) → b (StM m c)) - → ( m a → m c) -liftBaseOp_ f = \m → control $ \runInBase → f $ runInBase m -{-# INLINE liftBaseOp_ #-} +liftBaseOp_ :: MonadBaseControl b m + => (b (StM m a) -> b (StM m c)) + -> ( m a -> m c) +liftBaseOp_ f = \m -> control $ \runInBase -> f $ runInBase m +{-# INLINABLE liftBaseOp_ #-} -- | @liftBaseDiscard@ is a particular application of 'liftBaseWith' that allows -- lifting control operations of type: @@ -483,6 +504,24 @@ -- For example: -- -- @liftBaseDiscard forkIO :: 'MonadBaseControl' 'IO' m => m () -> m ThreadId@ -liftBaseDiscard ∷ MonadBaseControl b m ⇒ (b () → b a) → (m () → m a) -liftBaseDiscard f = \m → liftBaseWith $ \runInBase → f $ void $ runInBase m -{-# INLINE liftBaseDiscard #-} +liftBaseDiscard :: MonadBaseControl b m => (b () -> b a) -> (m () -> m a) +liftBaseDiscard f = \m -> liftBaseWith $ \runInBase -> f $ void $ runInBase m +{-# INLINABLE liftBaseDiscard #-} + +-- | @liftBaseOpDiscard@ is a particular application of 'liftBaseWith' that allows +-- lifting control operations of type: +-- +-- @((a -> b ()) -> b c)@ to: @('MonadBaseControl' b m => (a -> m ()) -> m c)@. +-- +-- 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 (runServer addr port) :: 'MonadBaseControl' 'IO' m => m () -> m ()@ +liftBaseOpDiscard :: MonadBaseControl b m + => ((a -> b ()) -> b c) + -> (a -> m ()) -> m c +liftBaseOpDiscard f g = liftBaseWith $ \runInBase -> f $ void . runInBase . g +{-# INLINABLE liftBaseOpDiscard #-} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/monad-control-0.3.2.1/NEWS new/monad-control-1.0.0.4/NEWS --- old/monad-control-0.3.2.1/NEWS 2013-04-23 18:40:21.000000000 +0200 +++ new/monad-control-1.0.0.4/NEWS 1970-01-01 01:00:00.000000000 +0100 @@ -1,362 +0,0 @@ -0.3 - -(Released on: Fri Dec 2 09:52:16 UTC 2011) - -* Major new API which IMHO is easier to understand than the old one. - -* On average about 60 times faster than the previous release! - -* New package lifted-base providing lifted versions of functions from the base - library. It exports the following modules: - - - Control.Exception.Lifted - - Control.Concurrent.Lifted - - Control.Concurrent.MVar.Lifted - - System.Timeout.Lifted - - Not all modules from base are converted yet. If you need a lifted version of - some function from base, just ask me to add it or send me a patch. - - -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) - -* Switched to git on github. - -* Tested with base-4.4 and ghc-7.2.1. - -* Use the new cabal test-suite feature. - - -0.2.0.1 - -(Released on: Wed Mar 16 15:53:50 UTC 2011) - -* Added laws for MonadTransControl and MonadControlIO - -* Bug fix: Add proper laziness to the MonadTransControl instances - of the lazy StateT, WriteT and RWST - These all failed the law: control $ \run -> run t = t - where t = return undefined - -* Add INLINABLE pragmas for most public functions - A simple benchmark showed some functions - (bracket and mask) improving by 30%. - - -0.2 - -(Released on: Wed Feb 9 12:05:26 UTC 2011) - -* Use RunInBase in the type of idLiftControl. - -* Added this NEWS file. - -* Only parameterize Run with t and use RankNTypes to quantify n and o - -liftControl :: (Monad m, Monad n, Monad o) => (Run t n o -> m a) -> t m a - +liftControl :: Monad m => (Run t -> m a) -> t m a - - -type Run t n o = forall b. t n b -> n (t o b) - +type Run t = forall n o b. (Monad n, Monad o, Monad (t o)) => t n b -> n (t o b) - - Bumped version from 0.1 to 0.2 to indicate this breaking change in API. - -* Added example of a derivation of liftControlIO. - Really enlightening! - - -0.1 - -(Released on: Sat Feb 5 23:36:21 UTC 2011) - -* Initial release - -This is the announcement message sent to the Haskell mailinglists: -http://www.mail-archive.com/[email protected]/msg23278.html - - -Dear all, - -Several attempts have been made to lift control operations (functions -that use monadic actions as input instead of just output) through -monad transformers: - -MonadCatchIO-transformers[1] provided a type class that allowed to -overload some often used control operations (catch, block and -unblock). Unfortunately that library was limited to those operations. -It was not possible to use, say, alloca in a monad transformer. More -importantly however, the library was broken as was explained[2] by -Michael Snoyman. In response Michael created the MonadInvertIO type -class which solved the problems. Then Anders Kaseorg created the -monad-peel library which provided an even nicer implementation. - -monad-control is a rewrite of monad-peel that uses CPS style -operations and exploits the RankNTypes language extension to simplify -and speedup most functions. A very preliminary and not yet fully -representative, benchmark shows that monad-control is on average about -2.6 times faster than monad-peel: - -bracket: 2.4 x faster -bracket_: 3.1 x faster -catch: 1.8 x faster -try: 4.0 x faster -mask: 2.0 x faster - -Note that, although the package comes with a test suite that passes, I -still consider it highly experimental. - - -API DOCS: - -http://hackage.haskell.org/package/monad-control - - -INSTALLING: - -$ cabal update -$ cabal install monad-control - - -TESTING: - -The package contains a copy of the monad-peel test suite written by -Anders. You can perform the tests using: - -$ cabal unpack monad-control -$ cd monad-control -$ cabal configure -ftest -$ cabal test - - -BENCHMARKING: - -$ darcs get http://bifunctor.homelinux.net/~bas/bench-monad-peel-control/ -$ cd bench-monad-peel-control -$ cabal configure -$ cabal build -$ dist/build/bench-monad-peel-control/bench-monad-peel-control - - -DEVELOPING: - -The darcs repository will be hosted on code.haskell.org ones that -server is back online. For the time being you can get the repository -from: - -$ darcs get http://bifunctor.homelinux.net/~bas/monad-control/ - - -TUTORIAL: - -This short unpolished tutorial will explain how to lift control -operations through monad transformers. Our goal is to lift a control -operation like: - -foo ∷ M a → M a - -where M is some monad, into a transformed monad like 'StateT M': - -foo' ∷ StateT M a → StateT M a - -The first thing we need to do is write an instance for the -MonadTransControl type class: - -class MonadTrans t ⇒ MonadTransControl t where - liftControl ∷ (Monad m, Monad n, Monad o) - ⇒ (Run t n o → m a) → t m a - -If you ignore the Run argument for now, you'll see that liftControl is -identical to the 'lift' method of the MonadTrans type class: - -class MonadTrans t where - lift ∷ Monad m ⇒ m a → t m a - -So the instance for MonadTransControl will probably look very much -like the instance for MonadTrans. Let's see: - -instance MonadTransControl (StateT s) where - liftControl f = StateT $ \s → liftM (\x → (x, s)) (f run) - -So what is this run function? Let's look at its type: - -type Run t n o = ∀ b. t n b → n (t o b) - -The run function executes a transformed monadic action 't n b' in the -non-transformed monad 'n'. In our case the 't' will be a StateT -computation. The only way to run a StateT computation is to give it -some state and the only state we have lying around is the one from the -outer computation: 's'. So let's run it on 's': - -instance MonadTransControl (StateT s) where - liftControl f = - StateT $ \s → - let run t = ... runStateT t s ... - in liftM (\x → (x, s)) (f run) - -Now that we are able to run a transformed monadic action, we're almost -done. Look at the type of Run again. The function should leave the -result 't o b' in the monad 'n'. This 't o b' computation should -contain the final state after running the supplied 't n b' -computation. In case of our StateT it should contain the final state -s': - -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) - -This final computation, "StateT $ \_ → return (x, s')", can later be -used to restore the final state. Now that we have our -MonadTransControl instance we can start using it. Recall that our goal -was to lift "foo ∷ M a → M a" into our StateT transformer yielding the -function "foo' ∷ StateT M a → StateT M a". - -To define foo', the first thing we need to do is call liftControl: - -foo' t = liftControl $ \run → ... - -This captures the current state of the StateT computation and provides -us with the run function that allows us to run a StateT computation on -this captured state. - -Now recall the type of liftControl ∷ (Run t n o → m a) → t m a. You -can see that in place of the ... we must fill in a value of type 'm -a'. In our case this will be a value of type 'M a'. We can construct -such a value by calling foo. However, foo expects an argument of type -'M a'. Fortunately we can provide one if we convert the supplied 't' -computation of type 'StateT M a' to 'M a' using our run function of -type ∀ b. StateT M b → M (StateT o b): - -foo' t = ... liftControl $ \run → foo $ run t - -However, note that the run function returns the final StateT -computation inside M. So the type of the right hand side is now -'StateT M (StateT o b)'. We would like to restore this final state. We -can do that using join: - -foo' t = join $ liftControl $ \run → foo $ run t - -That's it! Note that because it's so common to join after a -liftControl I provide an abstraction for it: - -control = join ∘ liftControl - -Allowing you to simplify foo' to: - -foo' t = control $ \run → foo $ run t - -Probably the most common control operations that you want to lift -through your transformers are IO operations. Think about: bracket, -alloca, mask, etc.. For this reason I provide the MonadControlIO type -class: - -class MonadIO m ⇒ MonadControlIO m where - liftControlIO ∷ (RunInBase m IO → IO a) → m a - -Again, if you ignore the RunInBase argument, you will see that -liftControlIO is identical to the liftIO method of the MonadIO type -class: - -class Monad m ⇒ MonadIO m where - liftIO ∷ IO a → m a - -Just like Run, RunInBase allows you to run your monadic computation -inside your base monad, which in case of liftControlIO is IO: - -type RunInBase m base = ∀ b. m b → base (m b) - -The instance for the base monad is trivial: - -instance MonadControlIO IO where - liftControlIO = idLiftControl - -idLiftControl directly executes f and passes it a run function which -executes the given action and lifts the result r into the trivial -'return r' action: - -idLiftControl ∷ Monad m ⇒ ((∀ b. m b → m (m b)) → m a) → m a -idLiftControl f = f $ liftM $ \r -> return r - -The instances for the transformers are all identical. Let's look at -StateT and ReaderT: - -instance MonadControlIO m ⇒ MonadControlIO (StateT s m) where - liftControlIO = liftLiftControlBase liftControlIO - -instance MonadControlIO m ⇒ MonadControlIO (ReaderT r m) where - liftControlIO = liftLiftControlBase liftControlIO - -The magic function is liftLiftControlBase. This function is used to -compose two liftControl operations, the outer provided by a -MonadTransControl instance and the inner provided as the argument: - -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) -liftLiftControlBase lftCtrlBase = - \f → liftControl $ \run → - lftCtrlBase $ \runInBase → - f $ liftM (join ∘ lift) ∘ runInBase ∘ run - -Basically it captures the state of the outer monad transformer using -liftControl. Then it captures the state of the inner monad using the -supplied lftCtrlBase function. If you recall the identical definitions -of the liftControlIO methods: 'liftLiftControlBase liftControlIO' you -will see that this lftCtrlBase function is the recursive step of -liftLiftControlBase. If you use 'liftLiftControlBase liftControlIO' in -a stack of monad transformers a chain of liftControl operations is -created: - -liftControl $ \run1 -> liftControl $ \run2 -> liftControl $ \run3 -> ... - -This will recurse until we hit the base monad. Then -liftLiftControlBase will finally run f in the base monad supplying it -with a run function that is able to run a 't m a' computation in the -base monad. It does this by composing the run and runInBase functions. -Note that runInBase is basically the composition: '... ∘ run3 ∘ run2'. - -However, just composing the run and runInBase functions is not enough. -Namely: runInBase ∘ run ∷ ∀ b. t m b → base (m (t m b)) while we need -to have ∀ b. t m b → base (t m b). So we need to lift the 'm (t m b)' -computation inside t yielding: 't m (t m b)' and then join that to get -'t m b'. - -Now that we have our MonadControlIO instances we can start using them. -Let's look at how to lift 'bracket' into a monad supporting -MonadControlIO. Before we do that I define a little convenience -function similar to 'control': - -controlIO = join ∘ liftControlIO - -Bracket just calls controlIO which captures the state of m and -provides us with a runInIO function which allows us to run an m -computation in IO: - -bracket ∷ MonadControlIO m - ⇒ m a → (a → m b) → (a → m c) → m c -bracket before after thing = - controlIO $ \runInIO → - E.bracket (runInIO before) - (\m → runInIO $ m >>= after) - (\m → runInIO $ m >>= thing) - -I welcome any comments, questions or patches. - -Regards, - -Bas - -[1] http://hackage.haskell.org/package/MonadCatchIO-transformers -[2] http://docs.yesodweb.com/blog/invertible-monads-exceptions-allocations/ -[3] http://hackage.haskell.org/package/monad-peel diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/monad-control-0.3.2.1/README.markdown new/monad-control-1.0.0.4/README.markdown --- old/monad-control-0.3.2.1/README.markdown 2013-04-23 18:40:21.000000000 +0200 +++ new/monad-control-1.0.0.4/README.markdown 2015-02-13 20:55:40.000000000 +0100 @@ -12,6 +12,6 @@ The package includes a copy of the `monad-peel` testsuite written by Anders Kaseorg The tests can be performed by using `cabal test`. -[This `critertion`](https://github.com/basvandijk/bench-monad-peel-control) +[This `criterion`](https://github.com/basvandijk/bench-monad-peel-control) based benchmark shows that `monad-control` is on average about 2.5 times faster than `monad-peel`. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/monad-control-0.3.2.1/monad-control.cabal new/monad-control-1.0.0.4/monad-control.cabal --- old/monad-control-0.3.2.1/monad-control.cabal 2013-04-23 18:40:21.000000000 +0200 +++ new/monad-control-1.0.0.4/monad-control.cabal 2015-02-13 20:55:40.000000000 +0100 @@ -1,5 +1,5 @@ Name: monad-control -Version: 0.3.2.1 +Version: 1.0.0.4 Synopsis: Lift control operations, like exception catching, through monad transformers License: BSD3 License-file: LICENSE @@ -26,13 +26,8 @@ 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 @criterion@ 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 +extra-source-files: README.markdown, CHANGELOG -------------------------------------------------------------------------------- @@ -42,23 +37,13 @@ -------------------------------------------------------------------------------- -Flag instanceST - Description: - If enabled this package will export MonadBaseControl instances for the lazy - and strict ST monad. If disabled these instances are only exported when base - >= 4.4. If enabled it is required that the transformer-base package exports - MonadBase instances for ST. It will do this by default. - Default: True - Library - if flag(instanceST) - CPP-options: -DINSTANCE_ST - Exposed-modules: Control.Monad.Trans.Control - Build-depends: base >= 3 && < 5 - , base-unicode-symbols >= 0.1.1 && < 0.3 - , transformers >= 0.2 && < 0.4 - , transformers-base >= 0.4.1 && < 0.5 + Build-depends: base >= 4.5 && < 5 + , stm >= 2.3 && < 3 + , transformers >= 0.2 && < 0.5 + , transformers-compat >= 0.3 && < 0.5 + , transformers-base >= 0.4.4 && < 0.5 Ghc-options: -Wall
