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 :: MonadCatchIO pr => (forall s. RegionT s pr α) -> pr α
- type TopRegion s = RegionT s IO
- runTopRegion :: (forall s. TopRegion s α) -> IO α
- forkTopRegion :: MonadIO pr => TopRegion s () -> RegionT s pr ThreadId
- data RegionalHandle resource r
- open :: (Resource resource, MonadCatchIO pr) => resource -> RegionT s pr (RegionalHandle resource (RegionT s pr))
- with :: (Resource resource, MonadCatchIO pr) => resource -> (forall s. RegionalHandle resource (RegionT s pr) -> RegionT s pr α) -> pr α
- class Dup α where
- class (Monad pr, Monad cr) => ParentOf pr cr
- 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 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`

.

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) | |

MonadCatchIO pr => MonadCatchIO (RegionT s pr) | |

Alternative pr => Alternative (RegionT s pr) | |

MonadIO pr => MonadIO (RegionT s pr) |

# Running regions

runRegionT :: MonadCatchIO 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 using `open`

, 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.)

An example of such a value is a `RegionalHandle`

. Regional handles are created by
opening a resource in a region using `open`

. Regional handles are parameterized by
the region in which they were created. So regional handles have this `s`

in their
type. This ensures that these regional handles, which may have been closed on exit
from this function, can't be returned from this function. This ensures you can
never do any IO with a closed regional handle.

Note that it is possible to run a region inside another region.

type TopRegion s = RegionT s IOSource

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
`forkTopRegion`

.

runTopRegion :: (forall s. TopRegion s α) -> IO αSource

Convenience funtion for running a *top-level* region in `IO`

.

Note that: `runTopRegion = `

`runRegionT`

forkTopRegion :: MonadIO pr => TopRegion s () -> RegionT s pr ThreadIdSource

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 (like `RegionalHandle`

s for example) can also be referenced in the forked
region.

For example the following is allowed:

runRegionT $ do regionalHndl <- open resource threadId <- forkTopRegion $ 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*.

# Opening resources

data RegionalHandle resource r Source

A handle to an opened resource parameterized by the `resource`

and the
region `r`

in which it was created.

Resource resource => Dup (RegionalHandle resource) |

open :: (Resource resource, MonadCatchIO pr) => resource -> RegionT s pr (RegionalHandle resource (RegionT s pr))Source

Open the given resource in a region yielding a regional handle to it.

Note that the returned regional handle is parameterized by the region in which it was created. This ensures that regional handles can never escape their region. And it also allows operations on regional handles to be executed in a child region of the region in which the regional handle was created.

Note that if you *do* wish to return a regional handle from the region in which
it was created you have to *duplicate* the handle by applying `dup`

to it.

with :: (Resource resource, MonadCatchIO pr) => resource -> (forall s. RegionalHandle resource (RegionT s pr) -> RegionT s pr α) -> pr αSource

A convenience function which opens the given resource, applies the given continuation function to the resulting regional handle and runs the resulting region.

Note that: `with resource f = `

.
`runRegionT`

(`open`

resource `>>=`

f)

# Duplication

Duplicate an `α`

in the parent region. This `α`

will usually be a
`(`

`RegionalHandle`

` resource)`

but it can be any value "derived" from this
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 resource (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 resource (RegionT ps ppr)`

Back in the parent region you can safely operate on `r1hDup`

.

dup :: MonadCatchIO ppr => α (RegionT cs (RegionT ps ppr)) -> RegionT cs (RegionT ps ppr) (α (RegionT ps ppr))Source

Resource resource => Dup (RegionalHandle resource) |

# Parent/child relationship between regions.

class (Monad pr, Monad cr) => ParentOf pr cr Source

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)))

# 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.