
On Tue, Nov 16, 2010 at 12:50 AM, Felipe Almeida Lessa
That said, I don't know what 'regions' may do for you that the simple monad I presented doesn't. Bas, what are the advantages?
My suggestion to use regions is based on an assumption which I'm not sure is right. Mitar can answer that... The assumption being that Mitar's Nerves are scarce resources (like files for example). Meaning: 1) They have an 'open' operation yielding a 'handle' to the 'resource': attach :: Nerve n -> IO (LiveNeuron n) Compare this with: openFile :: FilePath -> IOMode -> IO Handle 2) There are one or more operations defined on these handles: someOperation :: LiveNeuron n -> IO () (I'm not sure Mitar actually has this...) Compare this with: hFileSize :: Handle -> IO Integer 3) They have a 'close' operation: deattach :: LiveNeuron n -> IO () Compare with: hClose :: Handle -> IO () 4) It's important not to leave handles open (or in this case leave nerves attached) when they don't need to be. In the case of files when you leave a file open when you're not using it anymore, other processes may not be able to use the file. (I'm not sure this is a requirement for Nerves...) 5) It's an error to apply the operations to closed handles. In the case of files, the following program is an error for example: main = do h <- openFile "foo.txt" ReadMode hClose h hFileSize h -- error: h is already closed! (Again, I'm not sure a similar requirement exists for LiveNeurons) When these five requirements apply, you may find the regions package useful. When you write a correct 'regional' layer around your scarce resources like I showed earlier, regions will provide the following guarantees: * Resources are opened in a 'region'. When the region terminates (whether normally or by raising an exception) all opened resources will be closed automatically (this was Mitar's original requirement) * It's a type-error to reference closed resources. This ensures no operations can be applied to closed resources (deattached neurons). Besides these guarantees the regions package is very expressive. It allows you to nest regions inside each other and it allows you to 'duplicate' handles to ancestor regions. This allows you to use a resource, which was opened in a nested region, in the parent of that region, as in: example :: IO () example = runRegionT $ do sn' <- runRegionT $ do sn <- saveAttach Nerve -- We can't 'return sn' because the neuron will be deattached -- when the regions terminates. -- Instead we have to 'duplicate' it which ensures it stays -- attached in the current region and will only be deattached -- in the parent region: sn' <- dup sn return sn' -- Back in the parent region we can safely apply some operation -- to the duplicated neuron: someSaveOperation sn' To read more about regions, see both the API docs of regions: http://hackage.haskell.org/package/regions and some packages that define 'regional' layers over existing scarce resources like: * http://hackage.haskell.org/package/safer-file-handles * http://hackage.haskell.org/package/regional-pointers * http://hackage.haskell.org/package/usb-safe Finally, I can also recommend Oleg's and Chung-chieh's paper about "Lightweight monadic regions": http://okmij.org/ftp/Haskell/regions.html#light-weight Regards, Bas P.S. Please apply /s/save/safe to my previously posted code. It's late...