ANNOUNCE: New versions of ALL the monadic regions packages

Hello, As I explained in my announcement of 'safer-file-handles', I discovered a serious lack of expressive power in my 'regions' package. I have now solved that problem in the way I envisaged by removing the 'resource' parameter from 'RegionT' and using existential quantification to bring the 'resource' type back at the place I need it but hidden from the outside. Now you're able to open multiple types of resources in a single region which all will be closed automatically on termination of the region. These are the new releases: http://hackage.haskell.org/package/regions-0.2 http://hackage.haskell.org/package/regions-monadsfd-0.2 http://hackage.haskell.org/package/regions-monadstf-0.2.0.1 http://hackage.haskell.org/package/usb-safe-0.5 http://hackage.haskell.org/package/safer-file-handles-0.2 (Note that in the process I shuffled a bit with the API's. That's one of the reasons all these are major releases.) Do you want to see this in action? See 'example.hs' in the following package that demonstrates opening multiple different types of resources in a single region. The example extends the example in the 'usb-safe-examples' package by first opening a USB device (my USB mouse) and a temporary file in the same region. Next the device is configured, an interface is claimed and an alternate is set. Next some bytes are read from an endpoint of the device. Finally these bytes are written to the temporary file. It's fun to see this in action so do try it out: darcs get http://code.haskell.org/~basvandijk/code/usb-safe-and-safer-file-handles-exa... regards and see some of you at FP-NL tomorrow! Bas

BTW As can be seen from the documentation of 'safer-file-handles', I'm currently not satisfied at all about my implementation of the standard files (stdin, stdout and stderr). To quote the docs: BIG WARNING: I'm not satisfied with my current implementation of the standard handles (stdin, stdout and stderr)! Currently the standard handles are regional computations that return the regional file handles to the respected standard handles. There are 4 problems with this approach: * When the region terminates in which you call one of the standard handles the respected handle will be closed. I think this is not the expected behaviour. I would expect the standard handles to always remain open. * In System.IO the standard handles are pure values. My standard handles are monadic computations which makes them harder to work with. * There is no way to explicitly close a standard handle. Indeed, the whole purpose of lightweight monadic regions is to automatically close handles. However, when writing a Unix daemon for example, you need to be able to explicitly close the standard handles. * When reading 'man stdin' I'm confused if the standard handles are always open on program startup: quote 'man stdin': "...Under normal circumstances every Unix program has three streams opened for it when it starts up, one for input, one for output, and one for printing diagnostic or error messages..." "...The stdin, stdout, and stderr macros conform to C89 and this standard also stipulates that these three streams shall be open at program startup...." So now I'm confused... are these standard file handles always open on program startup or are there abnormal situations when they are closed? Maybe I just have to believe the documentation in System.IO which specifies that they are always initially open. If the standard handles are closed on startup using a handle returned from one of the standard handles will result in an exception! This would be a violation of my safety guarantees which is unacceptable. Does anyone have a solution or an rough idea how to solve it? Thanks, Bas

Hello Bas, Thursday, January 7, 2010, 6:25:34 PM, you wrote:
So now I'm confused... are these standard file handles always open on program startup or are there abnormal situations when they are closed?
afaik, parent process may close them before executing your program, it's used in particular for running daemons -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

On Thu, Jan 7, 2010 at 5:18 PM, Bulat Ziganshin
Hello Bas,
Thursday, January 7, 2010, 6:25:34 PM, you wrote:
So now I'm confused... are these standard file handles always open on program startup or are there abnormal situations when they are closed?
afaik, parent process may close them before executing your program, it's used in particular for running daemons
Thanks Bulat for explaining. Then I think the standard handles should have a type that at least encodes that they may be closed as in: stdin ∷ MonadCatchIO pr ⇒ RegionT s pr (Maybe (RegionalFileHandle R (RegionT s pr))) where Nothing means that the standard handle is closed. However this still leaves open problem 1, 2 and 3. Thanks, Bas

On Jan 7, 2010, at 14:44 , Bas van Dijk wrote:
On Thu, Jan 7, 2010 at 5:18 PM, Bulat Ziganshin
wrote: Thursday, January 7, 2010, 6:25:34 PM, you wrote:
So now I'm confused... are these standard file handles always open on program startup or are there abnormal situations when they are closed?
afaik, parent process may close them before executing your program, it's used in particular for running daemons
Thanks Bulat for explaining.
POSIX actually discourages that, because it's so common for library routines to assume they can write error messages to stderr; the approved way to handle daemons is to open the standard file handles on /dev/null, *not* to close them. There are systems that violate this, however (the most "fun" one I've encountered is Applications menu commands in Mac OS X 10.4's X11.app; bash partially works around it, but not entirely). So the correct thing to do is to check if they are open on startup, and if not open /dev/null. -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH

On Thu, Jan 07, 2010 at 04:00:31PM +0100, Bas van Dijk wrote:
As I explained in my announcement of 'safer-file-handles', I discovered a serious lack of expressive power in my 'regions' package. I have now solved that problem in the way I envisaged by removing the 'resource' parameter from 'RegionT' and using existential quantification to bring the 'resource' type back at the place I need it but hidden from the outside.
But if I understand correctly, now you can't know from the type signature what kind of resource a given code accesses. Isn't this a drawback? Wouldn't it be better to write something like TopRegion (File `And` Network) to tell something needs both? Cheers! -- Felipe.

On Thu, Jan 7, 2010 at 5:15 PM, Felipe Lessa
On Thu, Jan 07, 2010 at 04:00:31PM +0100, Bas van Dijk wrote:
As I explained in my announcement of 'safer-file-handles', I discovered a serious lack of expressive power in my 'regions' package. I have now solved that problem in the way I envisaged by removing the 'resource' parameter from 'RegionT' and using existential quantification to bring the 'resource' type back at the place I need it but hidden from the outside.
But if I understand correctly, now you can't know from the type signature what kind of resource a given code accesses. Isn't this a drawback? Wouldn't it be better to write something like
TopRegion (File `And` Network)
to tell something needs both?
Oh yes, very good point! Lets think, I could parameterize RegionT by some sort of heterogeneous list (HList) that encodes all the resources that the region opens. However won't this introduce my previous problem again? Another solution might be to encode the resources that a region opens as constraints. I think 'control-monad-exception' uses a similar technique to encode all the exceptions that a monadic computation may throw. My previous program could then possibly be written as something like: openBoth ∷ ( resources `Contains` Device , resources `Contains` File ) ⇒ Device → FilePath → RegionT resources pr () openBoth usbDevice filePath = do h1 ← open usbDevice h2 ← openFile filePath ReadMode return () Thanks for bringing up this point! Bas [1] http://hackage.haskell.org/package/control-monad-exception

On Thu, Jan 07, 2010 at 08:39:59PM +0100, Bas van Dijk wrote:
Another solution might be to encode the resources that a region opens as constraints. I think 'control-monad-exception' uses a similar technique to encode all the exceptions that a monadic computation may throw.
Yes, yes, that's what I had in mind, thanks for bringing it up. Although it isn't exatcly beautiful, GHC can infer the types and it works.
My previous program could then possibly be written as something like:
openBoth ∷ ( resources `Contains` Device , resources `Contains` File ) ⇒ Device → FilePath → RegionT resources pr () openBoth usbDevice filePath = do h1 ← open usbDevice h2 ← openFile filePath ReadMode return ()
I just don't see yet (maybe because I'm not well versed in monadic regions) how runRegionT will work. When working with exceptions, I have to provide a datatype that implements all the type classes I've used in my program. Hmmm... Perhaps an internal data type that is exposed and other modules instantiate? Cheers, -- Felipe.
participants (4)
-
Bas van Dijk
-
Brandon S. Allbery KF8NH
-
Bulat Ziganshin
-
Felipe Lessa