[Haskell-cafe] ANNOUNCE: safer-file-handles-0.1

Bas van Dijk v.dijk.bas at gmail.com
Thu Jan 7 05:50:12 EST 2010


I'm happy to announce another member in the 'monadic regions' family:


The package uses my 'regions' and 'explicit-iomodes' packages to add
two safety features on top of the regular System.IO file handles and

 * Regional file handles. Files must be opened in a region. When the
region terminates all opened files are automatically closed. The main
advantage of regions is that the handles to the opened files can not
be returned from the region which ensures no I/O with closed files is

 * Explicit IOModes. The regional file handles are parameterized by
the IOMode in which they were opened. All operations on handles
explicitly specify the needed IOMode. This way it is impossible to
read from a write-only handle or write to a read-only handle for

The primary technique used in this package is called "Lightweight
monadic regions" which was invented by Oleg Kiselyov and Chung-chieh
Shan. See:


This technique is implemented in the 'regions' package which is
re-exported from 'safer-file-handles'.

See the 'safer-file-handles-examples' package for examples how to use
this package:

darcs get http://code.haskell.org/~basvandijk/code/safer-file-handles-examples



While I wrote this message I realized a serious lack of expressive
power of my regions package. Namely that I can't write a program that
opens two different types of resources in the _same_ region. If for
example I want to combine my usb-safe package and this package the
following won't type-check:

openBoth ∷ Device → FilePath → IO ()
openBoth usbDevice filePath = runTopRegion $ do
  h1 ← open usbDevice             ∷ RegionT Device s IO
(RegionalHandle Device (RegionT Device s IO))
  h2 ← openFile filePath ReadMode ∷ RegionT File   s IO
(RegionalHandle File   (RegionT File   s IO))
  return ()

The reason, as can be seen from the types of the monadic actions, is
that the monad types differ between the two actions and bind ((>>=) ::
Monad m => m a -> (a -> m b) -> m b) obviously requires them to be the
same. The main problem thus, is that I parameterized the region with
the type of resources.

Note that I'm working on a solution where I remove the resource type
from RegionT. So instead of:

newtype RegionT resource s (pr ∷ * → *) α = RegionT
    { unRegionT ∷ ReaderT (IORef [Opened resource]) pr α }

I will have:

newtype RegionT s (pr ∷ * → *) α = RegionT
    { unRegionT ∷ ReaderT (IORef [SomeOpenedResource]) pr α }

data SomeOpenedResource = ∀ resource. Resource resource
                        ⇒ Some (Opened resource)

Hopefully I will be able to release this fix before FP-NL tomorrow.

More information about the Haskell-Cafe mailing list