regions 0.7.0.1 → 0.11
raw patch · 11 files changed
Files
- CONTRIBUTORS +6/−0
- Control/Monad/Trans/Region.hs +13/−14
- Control/Monad/Trans/Region/Internal.hs +292/−167
- Control/Monad/Trans/Region/OnExit.hs +6/−8
- Control/Monad/Trans/Region/ParentOf.hs +0/−70
- Control/Monad/Trans/Region/Unsafe.hs +23/−0
- Data/RegionRef.hs +0/−105
- LICENSE +1/−1
- NEWS +154/−0
- README.markdown +25/−0
- regions.cabal +15/−12
+ CONTRIBUTORS view
@@ -0,0 +1,6 @@+* Oleg Kiselyov and Chung-chieh Shan+ For coming up with the original idea of "lightweight monadic regions".++* Ben Franksen+ For rewriting the overly complicated ParentOf class and related instances+ to something really clean and simple exploiting TypeFamilies.
Control/Monad/Trans/Region.hs view
@@ -1,9 +1,7 @@-{-# LANGUAGE CPP #-}- ------------------------------------------------------------------------------- -- | -- Module : Control.Monad.Trans.Region--- Copyright : (c) 2009-2010 Bas van Dijk+-- Copyright : (c) 2009-2011 Bas van Dijk -- License : BSD3 (see the file LICENSE) -- Maintainer : Bas van Dijk <v.dijk.bas@gmail.com> --@@ -21,25 +19,26 @@ -- * Running regions , runRegionT - , TopRegion- , runTopRegion+ , RegionControlIO - -- ** Forking /top-level/ regions- , forkIOTopRegion- , forkOSTopRegion-#ifdef __GLASGOW_HASKELL__- , forkOnIOTopRegion-#endif -- * Duplication , Dup(dup) - , module Control.Monad.Trans.Region.ParentOf+ -- * Ancestor relation between regions+ , AncestorRegion - -- * Handy functions for writing monadic instances+ -- * Special regions+ -- ** The root region+ , RootRegion++ -- ** Local regions+ , LocalRegion, Local++ -- * Utilities for writing monadic instances , liftCallCC , mapRegionT , liftCatch ) where import Control.Monad.Trans.Region.Internal-import Control.Monad.Trans.Region.ParentOf+
Control/Monad/Trans/Region/Internal.hs view
@@ -1,15 +1,21 @@-{-# LANGUAGE CPP- , UnicodeSyntax- , NoImplicitPrelude- , GeneralizedNewtypeDeriving- , RankNTypes- , KindSignatures+{-# LANGUAGE CPP -- For portability.+ , UnicodeSyntax -- Makes it look so nice.+ , NoImplicitPrelude -- I like to be fully explicit.+ , GeneralizedNewtypeDeriving -- I'm lazy.+ , RankNTypes -- Provides the essential type-safety.+ , KindSignatures -- To help the type-checker.+ , EmptyDataDecls -- For the RootRegion type.+ , MultiParamTypeClasses -- For the AncestorRegion class.+ , UndecidableInstances -- For the AncestorRegion instances.+ , FlexibleInstances -- ,, ,, ,,+ , OverlappingInstances -- ,, ,, ,,+ , FlexibleContexts -- For unsafeLiftControl #-} ------------------------------------------------------------------------------- -- | -- Module : Control.Monad.Trans.Region.Internal--- Copyright : (c) 2009-2010 Bas van Dijk+-- Copyright : (c) 2009-2011 Bas van Dijk -- License : BSD3 (see the file LICENSE) -- Maintainer : Bas van Dijk <v.dijk.bas@gmail.com> --@@ -27,28 +33,35 @@ ( -- * Regions RegionT - -- * Close handles- , CloseAction- , CloseHandle+ -- * Registering finalizers+ , Finalizer+ , FinalizerHandle , onExit -- * Running regions , runRegionT - , TopRegion- , runTopRegion-- -- ** Forking /top-level/ regions- , forkIOTopRegion- , forkOSTopRegion-#ifdef __GLASGOW_HASKELL__- , forkOnIOTopRegion-#endif- -- * Duplication , Dup(dup) - -- * Handy functions for writing monadic instances+ -- * Ancestor relation between regions+ , AncestorRegion++ -- * Special regions+ -- ** The root region+ , RootRegion++ -- ** Local regions+ , LocalRegion, Local, unsafeStripLocal++ -- * MonadTransControl & MonadControlIO+ , RegionControlIO, unsafeLiftControlIO+ , unsafeLiftControl+ , unsafeControlIO+ , unsafeLiftIOOp+ , unsafeLiftIOOp_++ -- * Utilities for writing monadic instances , liftCallCC , mapRegionT , liftCatch@@ -60,13 +73,11 @@ -------------------------------------------------------------------------------- -- from base:-import Prelude ( (+), (-), seq, fromInteger )+import Prelude ( (+), (-), seq ) import Control.Applicative ( Applicative, Alternative )-import Control.Monad ( Monad, return, (>>=), fail- , (>>), when, forM_- , MonadPlus- )+import Control.Monad ( Monad, return, when, forM_, join, liftM, MonadPlus, ) import Control.Monad.Fix ( MonadFix )+import Control.Exception ( bracket ) import System.IO ( IO ) import Data.Function ( ($) ) import Data.Functor ( Functor )@@ -74,41 +85,46 @@ import Data.IORef ( IORef, newIORef , readIORef, modifyIORef, atomicModifyIORef )-import Control.Concurrent ( forkIO, forkOS, ThreadId )-#ifdef __GLASGOW_HASKELL__-import GHC.Conc ( forkOnIO )+#if __GLASGOW_HASKELL__ < 700+import Prelude ( fromInteger )+import Control.Monad ( (>>=), (>>), fail ) #endif --- from MonadCatchIO-transformers:-import Control.Monad.CatchIO ( MonadCatchIO, block, bracket )+-- from monad-control:+import Control.Monad.Trans.Control ( Run, RunInBase, liftControl )+import Control.Monad.IO.Control ( MonadControlIO, liftControlIO ) -- from transformers: import Control.Monad.Trans.Class ( MonadTrans, lift ) import Control.Monad.IO.Class ( MonadIO, liftIO ) import qualified Control.Monad.Trans.Reader as R ( liftCallCC, liftCatch )-import Control.Monad.Trans.Reader ( ReaderT(ReaderT)- , runReaderT, mapReaderT- )+import Control.Monad.Trans.Reader ( ReaderT(ReaderT), runReaderT, mapReaderT )+ -- from base-unicode-symbols: import Data.Eq.Unicode ( (≡) ) import Data.Function.Unicode ( (∘) ) +-- Handling the new asynchronous exceptions API in base-4.3:+#if MIN_VERSION_base(4,3,0)+import Control.Exception ( mask_ )+#else+import Control.Exception ( block )+mask_ ∷ IO α → IO α+mask_ = block+#endif + -------------------------------------------------------------------------------- -- * Regions -------------------------------------------------------------------------------- -{-| A monad transformer in which scarce resources can be opened-which are automatically closed when the region terminates.--Note that regions can be nested. @pr@ (for parent region) is a monad which is-usually the region which is running this region. However when you are running a-'TopRegion' the parent region will be 'IO'.+{-| A monad transformer in which scarce resources can be opened. When the region+terminates, all opened resources will be closed automatically. It's a type error+to return an opened resource from the region. The latter ensures no I/O with+closed resources is possible. -}-newtype RegionT s (pr ∷ * → *) α = RegionT- { unRegionT ∷ ReaderT (IORef [Handle]) pr α }-+newtype RegionT s pr α = RegionT (ReaderT (IORef [RefCountedFinalizer]) pr α) deriving ( Functor , Applicative , Alternative@@ -117,37 +133,62 @@ , MonadFix , MonadTrans , MonadIO- , MonadCatchIO ) -data Handle = Handle !CloseAction !(IORef RefCnt)+unRegionT ∷ RegionT s pr α → ReaderT (IORef [RefCountedFinalizer]) pr α+unRegionT (RegionT r) = r +-- | A 'Finalizer' paired with its reference count which defines how many times+-- it has been registered in some region.+data RefCountedFinalizer = RefCountedFinalizer !Finalizer !(IORef RefCnt)+ -- | An 'IO' computation that closes or finalizes a resource. For example--- @hClose@ or @free@.-type CloseAction = IO ()+-- \"@hClose someHandle@\" or \"@free somePtr@\".+type Finalizer = IO () type RefCnt = Int ----------------------------------------------------------------------------------- * Close handles+-- * Registering finalizers -------------------------------------------------------------------------------- --- | A handle to a 'CloseAction' that allows you to duplicate the action to a--- parent region using 'dup'.-newtype CloseHandle (r ∷ * → *) = CloseHandle Handle+{-| A handle to a 'Finalizer' that allows you to duplicate it to a parent region+using 'dup'. --- | Register the 'CloseAction' in the region. When the region terminates all--- registered close actions will be perfomed if they're not duplicated to a--- parent region.-onExit ∷ MonadIO pr ⇒ CloseAction → RegionT s pr (CloseHandle (RegionT s pr))-onExit closeAction = RegionT $ ReaderT $ \hsIORef → liftIO $ do- refCntIORef ← newIORef 1- let h = Handle closeAction refCntIORef- modifyIORef hsIORef (h:)- return $ CloseHandle h+Duplicating a finalizer means that instead of it being performed when the+current region terminates it is performed when the parent region terminates.+-}+newtype FinalizerHandle (r ∷ * → *) = FinalizerHandle RefCountedFinalizer +{-| Register the 'Finalizer' in the region. When the region terminates all+registered finalizers will be perfomed if they're not duplicated to a parent+region. +Note that finalizers are run in LIFO order (Last In First Out). So executing the following:++@+runRegionT $ do+ _ <- onExit $ putStrLn \"finalizer 1\"+ _ <- onExit $ putStrLn \"finalizer 2\"+ return ()+@++yields:++@+finalizer 2+finalizer 1+@+-}+onExit ∷ MonadIO pr ⇒ Finalizer → RegionT s pr (FinalizerHandle (RegionT s pr))+onExit finalizer = RegionT $ ReaderT $ \hsIORef → liftIO $ do+ refCntIORef ← newIORef 1+ let h = RefCountedFinalizer finalizer refCntIORef+ modifyIORef hsIORef (h:)+ return $ FinalizerHandle h++ -------------------------------------------------------------------------------- -- * Running regions --------------------------------------------------------------------------------@@ -167,111 +208,29 @@ Note that it is possible to run a region inside another region. -}-runRegionT ∷ MonadCatchIO pr ⇒ (∀ s. RegionT s pr α) → pr α-runRegionT m = runRegionWith [] m--{-| A region which has 'IO' as its parent region which enables it to be:-- * directly executed in 'IO' by 'runTopRegion',-- * concurrently executed in a new thread by 'forkIOTopRegion'.--}-type TopRegion s = RegionT s IO--{-| Convenience funtion for running a /top-level/ region in 'IO'.--Note that: @runTopRegion = 'runRegionT'@--}-runTopRegion ∷ (∀ s. TopRegion s α) → IO α-runTopRegion = runRegionT-------------------------------------------------------------------------------------- ** Forking /top-level/ regions-----------------------------------------------------------------------------------{-| Return a region which executes the given /top-level/ region in a new thread.--Note that the forked region has the same type variable @s@ as the resulting-region. This means that all values which can be referenced in the resulting-region can also be referenced in the forked region.--For example the following is allowed:--@-'runRegionT' $ do- regionalHndl <- open resource- threadId <- 'forkIOTopRegion' $ doSomethingWith regionalHndl- doSomethingElseWith regionalHndl-@--Note that the @regionalHndl@ and all other resources opened in the current-thread are closed only when the current thread or the forked thread terminates-whichever comes /last/.--}-forkIOTopRegion ∷ MonadIO pr ⇒ TopRegion s () → RegionT s pr ThreadId-forkIOTopRegion = forkTopRegion forkIO---- | Like 'forkIOTopRegion' but internally uses 'forkOS'.-forkOSTopRegion ∷ MonadIO pr ⇒ TopRegion s () → RegionT s pr ThreadId-forkOSTopRegion = forkTopRegion forkOS--#ifdef __GLASGOW_HASKELL__--- | Like 'forkIOTopRegion' but internally uses 'forkOnIO'.-forkOnIOTopRegion ∷ MonadIO pr ⇒ Int → TopRegion s () → RegionT s pr ThreadId-forkOnIOTopRegion = forkTopRegion ∘ forkOnIO-#endif--forkTopRegion ∷ MonadIO pr- ⇒ (IO () → IO ThreadId)- → (TopRegion s () → RegionT s pr ThreadId)-forkTopRegion doFork = \m →- RegionT $ ReaderT $ \hsIORef → liftIO $ do- hs ← readIORef hsIORef- block $ do- forM_ hs $ \(Handle _ refCntIORef) → increment refCntIORef- doFork $ runRegionWith hs m-------------------------------------------------------------------------------------- | Internally used function that actually runs the region on the given list of--- opened resources.-runRegionWith ∷ ∀ s pr α. MonadCatchIO pr- ⇒ [Handle] → RegionT s pr α → pr α-runRegionWith hs r = bracket (liftIO before)- (liftIO ∘ after)- (runReaderT $ unRegionT r)+runRegionT ∷ RegionControlIO pr ⇒ (∀ s. RegionT s pr α) → pr α+runRegionT r = unsafeLiftIOOp (bracket before after) thing where- before = newIORef hs+ before = newIORef []+ thing hsIORef = runReaderT (unRegionT r) hsIORef after hsIORef = do hs' ← readIORef hsIORef- forM_ hs' $ \(Handle closeAction refCntIORef) → do+ forM_ hs' $ \(RefCountedFinalizer finalizer refCntIORef) → do refCnt ← decrement refCntIORef- when (refCnt ≡ 0) closeAction---- | Internally used function that atomically decrements the reference count--- that is stored in the given @IORef@. The function returns the decremented--- reference count.-decrement ∷ IORef RefCnt → IO RefCnt-decrement ioRef = do atomicModifyIORef ioRef $ \refCnt →- let refCnt' = refCnt - 1- in (refCnt', refCnt')---- | Internally used function that atomically increments the reference count that--- is stored in the given @IORef@.-increment ∷ IORef RefCnt → IO ()-increment ioRef = do refCnt' ← atomicModifyIORef ioRef $ \refCnt →- let refCnt' = refCnt + 1- in (refCnt', refCnt')- refCnt' `seq` return ()+ when (refCnt ≡ 0) finalizer+ where+ decrement ∷ IORef RefCnt → IO RefCnt+ decrement ioRef = atomicModifyIORef ioRef $ \refCnt →+ let refCnt' = refCnt - 1+ in (refCnt', refCnt') -------------------------------------------------------------------------------- -- * Duplication -------------------------------------------------------------------------------- -{-| Duplicate an @α@ in the parent region. This @α@ will usually be-some type of regional handle.+{-| Duplicate an @h@ in the parent region. This @h@ will usually be some type of+regional handle. For example, suppose you run the following region: @@ -313,22 +272,188 @@ Back in the parent region you can safely operate on @r1hDup@. -}-class Dup α where- dup ∷ MonadCatchIO ppr- ⇒ α (RegionT cs (RegionT ps ppr))- → RegionT cs (RegionT ps ppr)- (α (RegionT ps ppr))+class Dup h where+ dup ∷ MonadIO ppr+ ⇒ h (RegionT cs (RegionT ps ppr))+ → RegionT cs (RegionT ps ppr)+ (h (RegionT ps ppr)) -instance Dup CloseHandle where- dup (CloseHandle h@(Handle _ refCntIORef)) =- lift $ RegionT $ ReaderT $ \hsIORef → liftIO $ block $ do- increment refCntIORef- modifyIORef hsIORef (h:)- return $ CloseHandle h+instance Dup FinalizerHandle where+ dup = lift ∘ copy +copy ∷ MonadIO pr+ ⇒ FinalizerHandle r+ → RegionT s pr (FinalizerHandle (RegionT s pr))+copy (FinalizerHandle h@(RefCountedFinalizer _ refCntIORef)) =+ RegionT $ ReaderT $ \hsIORef → liftIO $ mask_ $ do+ increment refCntIORef+ modifyIORef hsIORef (h:)+ return $ FinalizerHandle h +increment ∷ IORef RefCnt → IO ()+increment ioRef = do refCnt' ← atomicModifyIORef ioRef $ \refCnt →+ let refCnt' = refCnt + 1+ in (refCnt', refCnt')+ refCnt' `seq` return ()++ ----------------------------------------------------------------------------------- * Handy functions for writing monadic instances+-- * Ancestor relation between regions+--------------------------------------------------------------------------------++{-| The @AncestorRegion@ class is used to relate the region in which a resource+was opened to the region in which it is used. Take the following operation from+the @safer-file-handles@ package as an example:++@hFileSize :: (pr \`AncestorRegion\` cr, MonadIO cr) => RegionalFileHandle ioMode pr -> cr Integer@++The @AncestorRegion@ class defines the parent / child relationship between regions.+The constraint++@+ pr \`AncestorRegion\` cr+@++is satisfied if and only if @cr@ is a sequence of zero or more \"@'RegionT' s@\"+(with varying @s@) applied to @pr@, in other words, if @cr@ is an (improper)+nested subregion of @pr@.++The class constraint @InternalAncestorRegion pr cr@ serves two purposes. First, the+instances of @InternalAncestorRegion@ do the type-level recursion that implements+the relation specified above. Second, since it is not exported, user code cannot+add new instances of 'AncestorRegion' (as these would have to be made instances of+@InternalAncestorRegion@, too), effectively turning it into a /closed class/.+-}++-- The implementation uses type-level recursion, so it is no surprise we need+-- UndecidableInstances.++class (InternalAncestorRegion pr cr) ⇒ AncestorRegion pr cr++instance (InternalAncestorRegion pr cr) ⇒ AncestorRegion pr cr++class InternalAncestorRegion (pr ∷ * → *) (cr ∷ * → *)++instance InternalAncestorRegion (RegionT s m) (RegionT s m)+instance (InternalAncestorRegion pr cr) ⇒ InternalAncestorRegion pr (RegionT s cr)+++--------------------------------------------------------------------------------+-- * The root region+--------------------------------------------------------------------------------++{-| The @RootRegion@ is the ancestor of any region.++It's primary purpose is to tag regional handles which don't have an associated+finalizer. For example the standard file handles @stdin@, @stdout@ and @stderr@+which are opened on program startup and which shouldn't be closed when a region+terminates. Another example is the @nullPtr@ which is a memory pointer which+doesn't point to any allocated memory so doesn't need to be freed.+-}+data RootRegion α++instance InternalAncestorRegion RootRegion (RegionT s m)+++--------------------------------------------------------------------------------+-- * Local regions+--------------------------------------------------------------------------------++{-|+A @LocalRegion@ is used to tag regional handles which are created locally.++An example is the @LocalPtr@ in the @alloca@ function from the+@regional-pointers@ package:++@+alloca :: (Storable a, MonadControlIO pr)+ => (forall sl. LocalPtr a ('LocalRegion' sl s) -> RegionT ('Local' s) pr b)+ -> RegionT s pr b+@++The finalisation of the @LocalPtr@ is not performed by the @regions@ library but+is handled locally by @alloca@ instead.++The type variable @sl@, which is only quantified over the continuation, ensures+that locally opened resources don't escape.+-}+data LocalRegion sl s α++{-|+A type used to tag regions in which locally created handles (handles tagged with+'LocalRegion') can be used.++Note than any handle which is created in a @RegionT (Local s)@ can be used+outside that region (@RegionT s@) and visa versa+(except for 'LocalRegion'-tagged handles).+-}+data Local s++instance InternalAncestorRegion (LocalRegion sf s) (RegionT (Local s) m)++instance InternalAncestorRegion (RegionT s m) (RegionT (Local s) m)+instance InternalAncestorRegion (RegionT (Local s) m) (RegionT s m)++{-|+Convert a 'Local' region to a regular region.++This function is unsafe because it allows you to use a 'LocalRegion'-tagged+handle outside its 'Local' region.+-}+unsafeStripLocal ∷ RegionT (Local s) pr α → RegionT s pr α+unsafeStripLocal = RegionT ∘ unRegionT+++--------------------------------------------------------------------------------+-- * MonadTransControl & MonadControlIO+--------------------------------------------------------------------------------++{-|+Regions do not have an instance for 'MonadControlIO' since that would break the+safety guarantees. (Think about lifting 'forkIO' into a region!)++However 'runRegionT' and other operations on regions do need the ability to lift+control operations. This is where the 'RegionControlIO' class comes in. This+class is identical to `MonadControlIO` but its 'unsafeLiftControlIO' method is+not exported by this module. So user can't accidentally break the safety.++Note that a 'RegionT' is an instance of this class. For the rest there is a+catch-all @instance 'MonadControlIO' m => 'RegionControlIO' m@.+-}+class MonadIO m ⇒ RegionControlIO m where+ unsafeLiftControlIO ∷ (RunInBase m IO → IO α) → m α++instance RegionControlIO pr ⇒ RegionControlIO (RegionT s pr) where+ unsafeLiftControlIO f =+ unsafeLiftControl $ \runInPr →+ unsafeLiftControlIO $ \runInBase →+ let run = liftM (join ∘ lift) ∘ runInBase ∘ runInPr+ in f run++instance MonadControlIO m ⇒ RegionControlIO m where+ unsafeLiftControlIO = liftControlIO++--------------------------------------------------------------------------------++unsafeLiftControl ∷ Monad pr ⇒ (Run (RegionT s) → pr α) → RegionT s pr α+unsafeLiftControl f = RegionT $ liftControl $ \runReader →+ f $ liftM RegionT ∘ runReader ∘ unRegionT++unsafeControlIO ∷ RegionControlIO m ⇒ (RunInBase m IO → IO (m α)) → m α+unsafeControlIO = join ∘ unsafeLiftControlIO++unsafeLiftIOOp ∷ RegionControlIO m+ ⇒ ((α → IO (m β)) → IO (m γ))+ → ((α → m β) → m γ)+unsafeLiftIOOp f = \g → unsafeControlIO $ \runInIO → f $ runInIO ∘ g++unsafeLiftIOOp_ ∷ RegionControlIO m+ ⇒ (IO (m α) → IO (m β))+ → ( m α → m β)+unsafeLiftIOOp_ f = \m → unsafeControlIO $ \runInIO → f $ runInIO m++--------------------------------------------------------------------------------+-- * Utilities for writing monadic instances -------------------------------------------------------------------------------- -- | Lift a @callCC@ operation to the new monad.
Control/Monad/Trans/Region/OnExit.hs view
@@ -1,9 +1,7 @@-{-# LANGUAGE UnicodeSyntax #-}- ------------------------------------------------------------------------------- -- |--- Module : Control.Monad.Trans.Region.Unsafe--- Copyright : (c) 2009-2010 Bas van Dijk+-- Module : Control.Monad.Trans.Region.OnExit+-- Copyright : (c) 2009-2011 Bas van Dijk -- License : BSD3 (see the file LICENSE) -- Maintainer : Bas van Dijk <v.dijk.bas@gmail.com> --@@ -12,12 +10,12 @@ -- -------------------------------------------------------------------------------- -module Control.Monad.Trans.Region.OnExit ( CloseAction- , CloseHandle+module Control.Monad.Trans.Region.OnExit ( Finalizer+ , FinalizerHandle , onExit ) where -import Control.Monad.Trans.Region.Internal ( CloseAction- , CloseHandle+import Control.Monad.Trans.Region.Internal ( Finalizer+ , FinalizerHandle , onExit )
− Control/Monad/Trans/Region/ParentOf.hs
@@ -1,70 +0,0 @@-{-# LANGUAGE UnicodeSyntax- , NoImplicitPrelude- , KindSignatures- , MultiParamTypeClasses- , FunctionalDependencies- , UndecidableInstances- , FlexibleInstances- , OverlappingInstances- #-}------------------------------------------------------------------------------------ |--- Module : Control.Monad.Trans.Region.ParentOf--- Copyright : (c) 2009-2010 Bas van Dijk--- License : BSD3 (see the file LICENSE)--- Maintainer : Bas van Dijk <v.dijk.bas@gmail.com>--------------------------------------------------------------------------------------module Control.Monad.Trans.Region.ParentOf ( ParentOf ) where---- from base:-import Control.Monad ( Monad )---- from regions:-import Control.Monad.Trans.Region.Internal ( RegionT )---{-| The @ParentOf@ class declares the parent/child relationship between regions.--A region is the parent of another region if they're either equivalent like:--@-RegionT ps pr \`ParentOf\` RegionT ps pr-@--or if it is the parent of the parent of the child like:--@-RegionT ps ppr \`ParentOf\` RegionT cs- (RegionT pcs- (RegionT ppcs- (RegionT ps ppr)))-@--}-class (Monad pr, Monad cr) ⇒ pr `ParentOf` cr--instance Monad r ⇒ ParentOf r r--instance ( Monad cr- , cr `TypeCast2` RegionT s pcr- , pr `ParentOf` pcr- )- ⇒ ParentOf pr cr-------------------------------------------------------------------------------------- Type casting-----------------------------------------------------------------------------------class TypeCast2 (a ∷ * → *) (b ∷ * → *) | a → b, b → a-class TypeCast2' t (a ∷ * → *) (b ∷ * → *) | t a → b, t b → a-class TypeCast2'' t (a ∷ * → *) (b ∷ * → *) | t a → b, t b → a--instance TypeCast2' () a b ⇒ TypeCast2 a b-instance TypeCast2'' t a b ⇒ TypeCast2' t a b-instance TypeCast2'' () a a----- The End ---------------------------------------------------------------------
+ Control/Monad/Trans/Region/Unsafe.hs view
@@ -0,0 +1,23 @@+-------------------------------------------------------------------------------+-- |+-- Module : Control.Monad.Trans.Region.Unsafe+-- Copyright : (c) 2009-2011 Bas van Dijk+-- License : BSD3 (see the file LICENSE)+-- Maintainer : Bas van Dijk <v.dijk.bas@gmail.com>+--+--+--------------------------------------------------------------------------------++module Control.Monad.Trans.Region.Unsafe+ ( -- * Local regions+ unsafeStripLocal++ -- * MonadTransControl & MonadControlIO+ , unsafeLiftControlIO+ , unsafeLiftControl+ , unsafeControlIO+ , unsafeLiftIOOp+ , unsafeLiftIOOp_+ ) where++import Control.Monad.Trans.Region.Internal
− Data/RegionRef.hs
@@ -1,105 +0,0 @@-{-# LANGUAGE UnicodeSyntax, NoImplicitPrelude, KindSignatures #-}------------------------------------------------------------------------------------ |--- Module : Data.RegionRef--- Copyright : (c) 2009-2010 Bas van Dijk--- License : BSD3 (see the file LICENSE)--- Maintainer : Bas van Dijk <v.dijk.bas@gmail.com>------ A mutable variable in the region monad that should provide a safer--- replacement for an 'IORef' because you can't use it outside the region in--- which it was created (unless you explicitly duplicate it).--------------------------------------------------------------------------------------module Data.RegionRef- ( RegionRef- , pureDup- , newRegionRef- , readRegionRef- , writeRegionRef- , modifyRegionRef- , atomicModifyRegionRef- ) where------------------------------------------------------------------------------------- Imports------------------------------------------------------------------------------------- from base:-import Data.Function ( ($) )-import Control.Monad ( liftM )-import Data.Eq ( Eq )-import Data.IORef ( IORef- , newIORef- , readIORef, writeIORef- , modifyIORef, atomicModifyIORef- )---- from base-unicode-symbols:-import Data.Function.Unicode ( (∘) )---- from transformers:-import Control.Monad.IO.Class ( MonadIO, liftIO )---- from ourselves:-import Control.Monad.Trans.Region ( RegionT, ParentOf )-------------------------------------------------------------------------------------- Mutable references in the region monad------------------------------------------------------------------------------------- | A mutable variable storing a value of type @α@ which can only be used--- in region @r@, @r@'s children or @r@'s parent when you duplicate it using--- 'pureDup'.-newtype RegionRef (r ∷ * → *) α = RegionRef { unRegionRef ∷ IORef α }- deriving ( Eq )---- | Transform the region type @r@ of the regional reference to @r@'s parent so--- that it can be used in that region.-pureDup ∷ RegionRef (RegionT cs (RegionT ps ppr)) α- → RegionRef (RegionT ps ppr) α-pureDup = RegionRef ∘ unRegionRef--{-| Yield a regional computation that returns a new regional reference that-stores the given value.--Note that the reference is parameterized by the same region in which it was-created. This ensures you can never use this reference outside that region and-it allows you to use this reference in a child region of that region--}-newRegionRef ∷ MonadIO pr- ⇒ α → RegionT s pr (RegionRef (RegionT s pr) α)-newRegionRef = liftM RegionRef ∘ liftIO ∘ newIORef---- | Read the value of the given regional reference.-readRegionRef ∷ (pr `ParentOf` cr, MonadIO cr)- ⇒ RegionRef pr α → cr α-readRegionRef = liftIO ∘ readIORef ∘ unRegionRef---- | Write a new value into the given regional reference.-writeRegionRef ∷ (pr `ParentOf` cr, MonadIO cr)- ⇒ RegionRef pr α → α → cr ()-writeRegionRef ref x = liftIO $ writeIORef (unRegionRef ref) x---- | Mutate the contents of the given regional reference using the given--- function.-modifyRegionRef ∷ (pr `ParentOf` cr, MonadIO cr)- ⇒ RegionRef pr α → (α → α) → cr ()-modifyRegionRef ref f = liftIO $ modifyIORef (unRegionRef ref) f--{-| Atomically modifies the contents of the given regional reference using the-given function.--This function is useful for using a regional reference in a safe way in a-multithreaded program. If you only have one regional reference, then using-@atomicModifyRegionRef@ to access and modify it will prevent race conditions.--}-atomicModifyRegionRef ∷ (pr `ParentOf` cr, MonadIO cr)- ⇒ RegionRef pr α → (α → (α, β)) → cr β-atomicModifyRegionRef ref f = liftIO $ atomicModifyIORef (unRegionRef ref) f----- The End ---------------------------------------------------------------------
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2009-2010 Bas van Dijk+Copyright (c) 2009-2011 Bas van Dijk All rights reserved.
+ NEWS view
@@ -0,0 +1,154 @@+0.9++(Relased on: Wed Mar 9 12:20:05 UTC 2011)++* Removed Control.Monad.Trans.Region.Concurrent+ The fork functions contained bugs which could not be fixed.++* Removed Data.RegionRef+ I always considered this module a bit of a wart.++* Switch from monad-peel to monad-control.++* Added support for local regions+ Primarily needed for the alloca functions from the regional-pointers package.+++0.8.1++(Released on: Mon Jan 17 22:04:15 UTC 2011)++* Fixed bug: Forked threads should have the same masked state has their parents.++* Added forkIOUnmasked.++* Derived MonadTransPeel instance for RegionT.+++0.8++(Released on: Sat Nov 6 15:56:27 UTC 2010)++* Released during BelHac 2010!++* Replaced ParentOf class with the more understandable,+ easier to implement and safer AncestorRegion class.+ (Contributed by Ben Franksen)++ Also moved the class from its own module to the main:+ Control.Monad.Trans.Region module.++* Exported fork*TopRegion functions from their own dedicated module:+ Control.Monad.Trans.Region.Concurrent.++* Use MonadPeelIO instead of MonadCatchIO.++* Removed TopRegion and runTopRegion and+ renamed the fork functions accordingly.++* Renamed CloseAction to Finalizer and+ CloseHandle to FinalizerHandle.++* Added the RootRegion (empty) datatype which is defined as the+ ancestor of any region.+++0.7.0.1++(Released on: Sat Sep 11 14:17:48 UTC 2010)++* Added strictness flags to the arguments of the Handle data constructor.++* Fix haddock link.+++0.7++(Released on: Wed Sep 1 20:11:41 UTC 2010)++* Renamed forkTopRegion to forkIOTopRegion+ Also added forkOSTopRegion and forkOnIOTopRegion.+++0.6.0.1++(Released on: Wed Jun 16 13:45:27 UTC 2010)++* Removed outdated documentation.+++0.6++(Released on: Wed Jun 16 09:11:23 UTC 2010)++* Major change: removed the Resource class in favor of the much+ simpler 'onExit' function.++* Renamed Control.Monad.Trans.Region.Close to+ Control.Monad.Trans.Region.OnExit.+++0.5++(Released on: Sun May 2 20:24:19 UTC 2010)++* Renamed openResource and closeResource to open and close+ respectively The intention is that Control.Resource should be+ imported qualified.++* Updated dependencies+ transformers >= 0.2 && < 0.3+ MonadCatchIO-transformers >= 0.2 && < 0.3+ base-unicode-symbols >= 0.1.1 && < 0.3+++0.4++(Released on: Thu Feb 4 10:17:47 UTC 2010)++* Added Data.RegionRef.++* Moved the Resource class to its own module Control.Resource.++* Depend on more compatible versions of MonadCatchIO-transformers.++* Defined and exported liftCallCC.+++0.3++(Released on: Sat Jan 23 14:25:08 UTC 2010)++* Add 'mapInternalHandle'.++* Export the 'Dup' and 'ParentOf' classes from+ 'Control.Monad.Trans.Region'.+++0.2++(Released on: Thu Jan 7 14:14:15 UTC 2010)++* Renamed module Control.Monad.Trans.Region.Internal to+ Control.Monad.Trans.Region.Unsafe.++* Export only the unsafe things from Control.Monad.Trans.Region.Unsafe.++* Removed resource type from RegionT which prevented opening different+ types of resources in the same region.+++0.1.0.1++(Released on: Wed Dec 23 13:42:48 UTC 2009)++* Depend on base-unicode-symbols instead of unicode-symbols.++* Tested with base 4.2.+++0.1++(Released on: Mon Dec 21 09:46:51 UTC 2009)++* Initial release.
+ README.markdown view
@@ -0,0 +1,25 @@+This package provides the region monad transformer. Scarce resources+like files, memory pointers or USB devices for example can be opened+in a region. When the region terminates, all opened resources will be+automatically closed. The main advantage of regions is that the opened+resources can not be returned from the region which ensures no I/O+with closed resources is possible.++The primary technique used in this package is called "Lightweight+monadic regions" which was [invented][1] by Oleg Kiselyov and+Chung-chieh Shan.++Also see the [regions-mtl] and [regions-monadstf] packages which+provide instances for the classes in the respected monad transformers+packages.++For an example on how to use this library see the+[safer-file-handles], [usb-safe] or [regional-pointers] packages.++[1]: http://okmij.org/ftp/Haskell/regions.html#light-weight++[regions-mtl]: http://hackage.haskell.org/package/regions-mtl+[regions-monadstf]: http://hackage.haskell.org/package/regions-monadstf+[safer-file-handles]: http://hackage.haskell.org/package/safer-file-handles+[usb-safe]: http://hackage.haskell.org/package/usb-safe+[regional-pointers]: http://hackage.haskell.org/package/regional-pointers
regions.cabal view
@@ -1,12 +1,14 @@ name: regions-version: 0.7.0.1+version: 0.11 cabal-version: >=1.6 build-type: Simple license: BSD3 license-file: LICENSE-copyright: 2009-2010 Bas van Dijk+copyright: 2009-2011 Bas van Dijk author: Bas van Dijk maintainer: Bas van Dijk <v.dijk.bas@gmail.com>+homepage: https://github.com/basvandijk/regions/+bug-reports: https://github.com/basvandijk/regions/issues stability: experimental category: Control, Monadic Regions synopsis: Provides the region monad for safely opening and working with@@ -24,24 +26,25 @@ . <http://okmij.org/ftp/Haskell/regions.html#light-weight> .- Also see the @regions-monadsfd@ and @regions-monadstf@ packages which provide- instances for the classes in the respected monads packages.+ Also see the @regions-mtl@ and @regions-monadstf@ packages which provide+ instances for the classes in the respected monad transformers packages. . For an example on how to use this library see the @safer-file-handles@, @usb-safe@ or @regional-pointers@ packages. +extra-source-files: README.markdown, NEWS, CONTRIBUTORS+ source-repository head- Type: darcs- Location: http://code.haskell.org/~basvandijk/code/regions+ Type: git+ Location: git://github.com/basvandijk/regions.git Library GHC-Options: -Wall- build-depends: base >= 4 && < 4.3- , base-unicode-symbols >= 0.1.1 && < 0.3- , transformers >= 0.2 && < 0.3- , MonadCatchIO-transformers >= 0.2 && < 0.3+ build-depends: base >= 4 && < 4.5+ , base-unicode-symbols >= 0.1.1 && < 0.3+ , transformers >= 0.2 && < 0.3+ , monad-control >= 0.2 && < 0.3 exposed-modules: Control.Monad.Trans.Region- Control.Monad.Trans.Region.ParentOf Control.Monad.Trans.Region.OnExit- Data.RegionRef+ Control.Monad.Trans.Region.Unsafe other-modules: Control.Monad.Trans.Region.Internal