}9     #Bas van Dijk <v.dijk.bas@gmail.com> Class of scarce: resources. A scarce resource is a resource that only one Guser can use at a time. (like a file, memory pointer or USB device for  example). 4Because of the scarcity, these resources need to be opened to grant temporary Psole access to the resource. When the resource is no longer needed it should be closed1 a.s.a.p to grant others access to the resource.  Yield an IO9 computation that opens the given resource and returns a  Handle on it. HThink of a handle as your private session with the resource. As long as  you have it, other users can't use the resource. So don't forget to close . this session with the resource as soon as you're done with it.  Yield an IO8 computation that closes the resource identified by the  given Handle. Warning : Using the Handle) after the resource has been closed will : usually throw an exception or result in a program crash! #Bas van Dijk <v.dijk.bas@gmail.com>The ParentOf class declares the parent/$child relationship between regions. 0A region is the parent of another region if they're either equivalent like:  RegionT ps pr `ParentOf` RegionT ps pr 8or if it is the parent of the parent of the child like:  RegionT ps ppr `ParentOf` RegionT cs + (RegionT pcs . (RegionT ppcs 5 (RegionT ps ppr)))  Duplicate an  in the parent region. This  will usually be a ( resource) but it can be any value "derived" from this regional handle. 3For 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. 6Suppose 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. HHowever, if you duplicate the regional handle you can safely return it.   r1hDup < - dup r1h  return r1hDup  Note that 2r1hDup :: RegionalHandle resource (RegionT ps ppr) 4Back in the parent region you can safely operate on r1hDup. A region which has . as its parent region which enables it to be:  directly executed in  by  , * concurrently executed in a new thread by  . 4A handle to an opened resource parameterized by the resource and the  region r in which it was created.  8Get the internal handle from the given regional handle. Warning:> This function should not be exported to or used by end-users Q because it allows them to close the handle manually, which will defeat the 4 safety-guarantees that this package provides! Tip: If you enable the  ViewPatterns language extension you can use  internalHandle8 as a view-pattern as in the following example from the  usb-safe package:   resetDevice :: (pr `ParentOf` cr, MonadIO cr) ; -> RegionalHandle USB.Device pr -> cr () ? resetDevice (internalHandle -> (DeviceHandle ...)) = ...  8Get the reference count from the given regional handle. ?Normally a handle should be closed when its originating region 9 terminates. There are two exceptions to this rule:  When a handle is  duplicated to a parent region using  D it should only be closed when the parent region terminates. 1 When a region is executed in a new thread using   all P handles that can be referenced in the originating region should also be W referenceable in the new forked region. Therefore those handles should only be P closed when the originating region or the new forked region terminates,  whichever comes last. <To implement this behaviour, handles are reference counted.  The reference count is:  Initialized at 1 in .  Incremented in  and  .  Decremented on termination of !  (which is called by   and  ). FOnly when the reference count reaches 0 will the resource actually be  closed. "GAn internally used datatype which adds an existential wrapper around a   to hide the resource type. If the resource6 type is not hidden, regions must be parameterized by N it. This is undesirable because then only one type of resource can be opened L in a region. The following allows all types of resources to be opened in a 4 single region as long as they have an instance for . # <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 Pusually the region which is running this region. However when you are running a  the parent region will be . $%&MInternally used function that atomically decrements the reference count that is stored in the given IORef1. The function returns the decremented reference count. 'MInternally used function that atomically increments the reference count that  is stored in the given IORef. *Execute a region inside its parent region pr. ?All resources which have been opened in the given region using  , and which haven't been duplicated using ,, will be closed on exit from this function 9wether by normal termination or by raising an exception. QAlso 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 s7 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 ". Regional handles are created by %opening a resource in a region using (. Regional handles are parameterized by Ethe region in which they were created. So regional handles have this s in their Stype. This ensures that these regional handles, which may have been closed on exit from this function, can'7t 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. "Convenience funtion for running a  top-level region in .  Note that: runTopRegion =   )Return a region which executes the given  top-level region in a new thread. 7Note that the forked region has the same type variable s as the resulting Lregion. This means that all values which can be referenced in the resulting  region (like 4s 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 Othread are closed only when the current thread or the forked thread terminates whichever comes last. !LInternally used function that actually runs the region on the given list of  opened resources. FOpen the given resource in a region yielding a regional handle to it. ONote that the returned regional handle is parameterized by the region in which Jit was created. This ensures that regional handles can never escape their Nregion. And it also allows operations on regional handles to be executed in a Echild 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  to it. IA convenience function which opens the given resource, applies the given Ncontinuation function to the resulting regional handle and runs the resulting region.  Note that: with resource f =   ( resource ( f). )Internally used function to register the given opened resource by  consing3 it to the list of opened resources of the region. Lift a callCC operation to the new monad. +Transform the computation inside a region. Lift a  catchError operation to the new monad. catch on the argument monad. Computation to attempt. Exception handler.   #Bas van Dijk <v.dijk.bas@gmail.com>   #Bas van Dijk <v.dijk.bas@gmail.com> +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  . *+Transform the region type r of the regional reference to r' s parent so % that it can be used in that region. HYield a regional computation that returns a new regional reference that stores the given value. LNote that the reference is parameterized by the same region in which it was Ocreated. This ensures you can never use this reference outside that region and Eit allows you to use this reference in a child region of that region 0Read the value of the given regional reference. 5Write a new value into the given regional reference. DMutate the contents of the given regional reference using the given  function. KAtomically modifies the contents of the given regional reference using the given function. JThis function is useful for using a regional reference in a safe way in a Kmultithreaded program. If you only have one regional reference, then using atomicModifyRegionRef7 to access and modify it will prevent race conditions. #Bas van Dijk <v.dijk.bas@gmail.com>;Modify the internal handle from the given regional handle.   ,      !"#$%&'()*+,-./0123 regions-0.4Control.ResourceControl.Monad.Trans.Region!Control.Monad.Trans.Region.UnsafeData.RegionRef#Control.Monad.Trans.Region.InternalResourceHandle openResource closeResourceParentOfDupdup TopRegionRegionalHandleinternalHandleRegionT runRegionT runTopRegion forkTopRegionopenwith liftCallCC mapRegionT liftCatch RegionRefpureDup newRegionRef readRegionRefwriteRegionRefmodifyRegionRefatomicModifyRegionRefmapInternalHandle TypeCast2'' TypeCast2' TypeCast2ghc-prim GHC.TypesIO refCntIORef runRegionWithAnyRegionalHandleAny unRegionT decrement incrementbaseGHC.Base>>=register unRegionRef