Maintainer | Bas van Dijk <v.dijk.bas@gmail.com> |
---|
This modules implements a technique called "Lightweight monadic regions" invented by Oleg Kiselyov and Chung-chieh Shan
- data RegionT s pr α
- runRegionT :: MonadPeelIO pr => (forall s. RegionT s pr α) -> pr α
- class Dup α where
- class InternalAncestorRegion pr cr => AncestorRegion pr cr
- data RootRegion α
- liftCallCC :: (((α -> pr β) -> pr α) -> pr α) -> ((α -> RegionT s pr β) -> RegionT s pr α) -> RegionT s pr α
- mapRegionT :: (m α -> n β) -> RegionT s m α -> RegionT s n β
- liftCatch :: (pr α -> (e -> pr α) -> pr α) -> RegionT s pr α -> (e -> RegionT s pr α) -> RegionT s pr α
Regions
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.
InternalAncestorRegion pr cr => InternalAncestorRegion pr (RegionT s cr) | |
InternalAncestorRegion RootRegion (RegionT s m) | |
MonadTrans (RegionT s) | |
Monad pr => Monad (RegionT s pr) | |
Functor pr => Functor (RegionT s pr) | |
MonadFix pr => MonadFix (RegionT s pr) | |
MonadPlus pr => MonadPlus (RegionT s pr) | |
Applicative pr => Applicative (RegionT s pr) | |
Alternative pr => Alternative (RegionT s pr) | |
MonadPeelIO pr => MonadPeelIO (RegionT s pr) | |
MonadIO pr => MonadIO (RegionT s pr) | |
InternalAncestorRegion (RegionT s m) (RegionT s m) |
Running regions
runRegionT :: MonadPeelIO pr => (forall s. RegionT s pr α) -> pr αSource
Execute a region inside its parent region pr
.
All resources which have been opened in the given region and which haven't been
duplicated using dup
, will be closed on exit from this function wether by
normal termination or by raising an exception.
Also all resources which have been duplicated to this region from a child region are closed on exit if they haven't been duplicated themselves.
Note the type variable s
of the region wich is only quantified over the region
itself. This ensures that all values, having a type containing s
, can not
be returned from this function. (Note the similarity with the ST
monad.)
Note that it is possible to run a region inside another region.
Duplication
Duplicate an α
in the parent region. This α
will usually be
some type of regional handle.
For example, suppose you run the following region:
runRegionT $ do
Inside this region you run a nested child region like:
r1hDup <- runRegionT $ do
Now in this child region you open the resource r1
:
r1h <- open r1
...yielding the regional handle r1h
. Note that:
r1h :: RegionalHandle (RegionT cs (RegionT ps ppr))
where cs
is bound by the inner (child) runRegionT
and ps
is
bound by the outer (parent) runRegionT
.
Suppose you want to use the resulting regional handle r1h
in the parent
region. You can't simply return r1h
because then the type variable cs
,
escapes the inner region.
However, if you duplicate the regional handle you can safely return it.
r1hDup <- dup r1h return r1hDup
Note that r1hDup :: RegionalHandle (RegionT ps ppr)
Back in the parent region you can safely operate on r1hDup
.
Ancestor relation between regions
class InternalAncestorRegion pr cr => AncestorRegion pr cr Source
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 "
"
(with varying RegionT
ss
) 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.
InternalAncestorRegion pr cr => AncestorRegion pr cr |
data RootRegion α Source
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.
InternalAncestorRegion RootRegion (RegionT s m) |
Handy functions for writing monadic instances
liftCallCC :: (((α -> pr β) -> pr α) -> pr α) -> ((α -> RegionT s pr β) -> RegionT s pr α) -> RegionT s pr αSource
Lift a callCC
operation to the new monad.
mapRegionT :: (m α -> n β) -> RegionT s m α -> RegionT s n βSource
Transform the computation inside a region.