Re: Sets of IOErrors?

1999-09-30 Thread Fergus Henderson

On 29-Sep-1999, Marcin 'Qrczak' Kowalczyk [EMAIL PROTECTED] wrote:
 I only don't like the details about IOError. It's not extensible
 and Dynamic is still not nice. I have no idea how to make it
 better. Probably some general way of making extensible datatypes.

Could you explain what you don't like about Dynamic?

-- 
Fergus Henderson [EMAIL PROTECTED]  |  "I have always known that the pursuit
WWW: http://www.cs.mu.oz.au/~fjh  |  of excellence is a lethal habit"
PGP: finger [EMAIL PROTECTED]| -- the last words of T. S. Garp.






Re: Sets of IOErrors?

1999-09-29 Thread Fergus Henderson

On 08-Sep-1999, Alastair Reid [EMAIL PROTECTED] wrote:
 
 I recently had occasion to write this function:
 
   -- do a, if that fails do b, if that fails, raise b's exception
   (?) :: IO a - IO a - IO a
   a ? b = a `catch` \_ - b 
 
 Simple enough, but if b fails, I don't really want to raise b's
 exception, I want to raise both a's exception and b's exception.

Yes, that kind of thing is not that uncommon.

BTW, you didn't explain why you need to raise both exceptions.
The reason is to correctly handle the case where programs test the
type of the exception raised and attempt some corrective action
accordingly.  For example, a program which is attempting to access a
network might have a high-level exception handler that checks for
network I/O errors and tries to handle them by restarting the network
connection and then retrying.  If a network I/O error occurs, and then
a lower-level handler tries some alternative means of recovery, and
that alternative throws some other kind of exception, it's important
that the exception thrown to the higher-level handler still include the
information that a network I/O error occurred, so that the higher-level
handler will restart the network connection.

The C++ standardization committee considered the issue of multiple
exceptions, and basically decided that it was too difficult to deal
with.  If a C++ exception handler itself throws an exception, then the
default behaviour is to abort the program.  You can install a special
handler to deal with such situtations, but that special handler can't
throw an exception, so there's not much it can safely do other than to
abort.  In theory it's possible to program around that kind of thing in
C++, but in practice this is exceedingly difficult (for various
reasons, including problems related to memory management and the lack
of a clone() member in the std::exception class), and furthermore
requires agreement between the different parts of the program about how
sets of exceptions are represented, so in practice nobody does it, as
far as I am aware.

It would be nice if Haskell could handle that problem better than C++.
Automatic memory management and the ease of writing higher-order combinators
such as `?' above mean that it is already much easier in Haskell.
However, some kind of standard library support is also essential if
library packages written by different authors are to cooperate.
So I agree with the essence of Alistair Reid's suggestions.
However, I have some quibbles about the details.

 What
 I'd like (in some future version of Haskell) is an IOError constructor
 which lets me merge two IOErrors together and appropriate operations
 to test for it and, perhaps, take it apart:
 
   IO.multipleErrors   :: [IOError] - IOError
   IO.isMultipleErrors :: IOError - Bool
   IO.ioeGetErrors :: IOError - [IOError]
 
 The intention is that an IOError is a non-empty list of atomic errors
 (ie any of the existing IOErrors).  Thus "multipleErrors" is
 essentially concat, ioeGetErrors is (essentially) the identity
 function (it returns a list of IOErrors which are guaranteed to be
 non-empty) and all existing functions for testing IOErrors are
 modified to be defined only over singleton lists.

What existing functions for testing IOErrors?
Apart from the Eq and Show classes, Haskell 98 doesn't define any, AFAIK.
If you're suggesting that Eq or Show be undefined for IOErrors that
represent sets of exceptions, then I would have to disagree...

Perhaps you meant the Hugs/ghc functions for testing Exceptions.
If so, the above suggestions should be revised to refer to Exceptions
rather than IOErrors.

The exception handling in Haskell 98 needs substantial work, IMHO.
IMHO Haskell 200X should pick up the Hugs/ghc extensions related to
exception handling, or something along those lines, in particular:
(a) allow throwing exceptions from arbitrary code, not just from within
the IO monad
(b) allow throwing and catching of dynamically typed values,
e.g. using an interface like the Hugs/ghc Dynamic library

Once you have (b), then supporting sets of exceptions is straight-forward.
However, to handle the multiple exceptions problem, support for sets of
exceptions still needs to be part of the standard library, to ensure that
applications and library packages cooperate in this respect.

-- 
Fergus Henderson [EMAIL PROTECTED]  |  "I have always known that the pursuit
WWW: http://www.cs.mu.oz.au/~fjh  |  of excellence is a lethal habit"
PGP: finger [EMAIL PROTECTED]| -- the last words of T. S. Garp.






Re: Sets of IOErrors?

1999-09-29 Thread Fergus Henderson

On 28-Sep-1999, Alastair Reid [EMAIL PROTECTED] wrote:
 
 Fergus Henderson [EMAIL PROTECTED] replied:
  What existing functions for testing IOErrors?
  Apart from the Eq and Show classes, Haskell 98 doesn't define any, AFAIK.
 
 The IO library defines these functions.
 (http://haskell.cs.yale.edu/onlinelibrary/io.html)
 
  isAlreadyExistsError  :: IOError - Bool
  isDoesNotExistError   :: IOError - Bool
  isAlreadyInUseError   :: IOError - Bool
  isFullError   :: IOError - Bool
  isEOFError:: IOError - Bool
  isIllegalOperation:: IOError - Bool
  isPermissionError :: IOError - Bool
  isUserError   :: IOError - Bool
  ioeGetErrorString :: IOError - String
  ioeGetHandle  :: IOError - Maybe Handle
  ioeGetFileName:: IOError - Maybe FilePath

Oh, of course.  Thanks for the correction.  (I searched the Haskell 98
Report but I forgot to search the Haskell 98 Library Report.)

...
 I was going to suggest that we redefine isAlreadyExistsError and
 friends to return true if the associated error is a member of the set.
 But if we do this, what do we do with ioeGetErrorString and friends?

Deprecate them.
Define them to return the value associated with the first matching
exception, but deprecate them, and instead provide alternatives
that work with sets of exceptions.

  (b) allow throwing and catching of dynamically typed values,
  e.g. using an interface like the Hugs/ghc Dynamic library
 
 Despite having written a good deal of the Hugs-GHC Dynamic library[2],
 I'm wary of making it part of the standard because it is limited to
 handling monomorphic values only: no polymorphism, no overloading.

I'm not entirely certain that I understand what you mean by
"no polymorphism, no overloading".

If you want to put a polymorphic overloaded function into a Dynamic,
you can just put it in a wrapper data structure and put the wrapper
into a Dynamic, and then you can get that wrapper out of the
Dynamic and then get the polymorphic overloaded function out of
the wrapper.  (This presumes that the language supports first-class
polymorphism in data structures, but ghc supports that, and I think
it is likely that Haskell 200X will.)

I presume, then, that what you are talking about the difficulty of
putting a monomorphically typed value into a Dynamic and then
later extracting it with a polymophic or overloaded type.

Extracting values with polymorphic types can be solved using
existential types.  This technique is used in the Mercury standard
library (versions rotd-1998-11-19 and greater).  Using this technique
can be a little cumbersome, but it gets the job done.  It does require
a small extension to the current Dynamic interface, specifically a
function analagous to the `univ_value' function in the Mercury standard
library, but that extension would be trivial to implement once you have
existential types.

Extracting values with overloaded types requires what I called
"dynamic type class casts".  I agree that the lack of support for
this is a problematic limitation.

So, if a better solution comes along before Haskell 200X is finalized,
that would be great.  But failing that, I think something like the
Hugs-GHC Dynamic library is certainly much better than using a
non-extensible Exception type, even if does not solve all the problems
that we would like it to solve.

 I'm also a little leery of the lack of structure that would result
 from using dynamic typing to provide extensibility.  The hierarchial
 organisation of exceptions in Java and other OO languages seems to be
 a good match to the task.

Well, C++ and Java certainly use dynamic typing in their exception handling.
The difference is that those languages support the equivalent of
dynamic type class casts, whereas the Hugs/ghc Dynamic library does not.

Certainly it would be nicer to impose more structure.
And if/when Haskell gets support for type class casts or something
equivalent, then as you say we can do that using Haskell's type
class system.

But if dynamic type class casts or something with similar functionality
don't arrive in time for Haskell 200X, then we will need an interim
solution.  Currently the only alternative is to encode all exception
types into strings.  Using Dynamic could hardly be worse.  If the
choice is between strings and Dynamic, then I'll choose Dynamic every
time.

Note that Ada 95 used strings, and so the Ada 95 experts in
comp.lang.ada recommend using serialization techniques to encode
arbitrary data types in strings for the purposes of exception
handling.  I surely hope that Haskell 200X experts don't have to
recommend the same advice.

 (Though, again, how does this interact with having sets of errors?)

I don't think that is a problem for hierarchical classification.
You just have to apply the dynamic type class cast (or equivalent)
to every member of the set and collect the set of results.

-- 
Fergus Henderson [EMAIL PROTECTED]  |  "I have always known that the pursuit
WWW: 

Re: Sets of IOErrors?

1999-09-29 Thread Fergus Henderson

On 28-Sep-1999, Alastair Reid [EMAIL PROTECTED] wrote:
 
(b) allow throwing and catching of dynamically typed values,
e.g. using an interface like the Hugs/ghc Dynamic library
 
 [discussion of Dynamic library, etc deleted]
 
 [The following is a bit of a straw-man: it doesn't quite work but
 may have good parts which can be used in other designs.]
 
 (part of) Another approach is to extend Haskell with extensible
 datatypes as is done in ML.
...
 If Haskell supported extensible datatypes, it would be easy to define a
 hierarchy of exception values.
...
 Disadvantages of this approach include:
 
 o Most Haskell features can be described as "just syntactic sugar"
   - it's hard to do this here.
 
 o It's hard to write total functions over extensible datatypes (eg
   try writing a Show function for the attached definition of IOError).
 
 o This is the only compelling use for extensible datatypes - wouldn't
   it be better to support exception handling more directly?

Another disadvantage is that with this approach you miss out on
multiple inheritance.  Your example categorization

   IOError
 Win32Error
   GDIError
 BadRegion
 BadBrush
 PosixError
   ENOTDIR
   ENAMETOOLONG
   EINTR
 UserError
 AlreadyExists

categorizes errors according to the subsystem that produced them
(Win32, Posix), but often you want to categorize errors differently,
and some errors may fall into multiple categories.

Note that using `Dynamic', you could easily implement the same kind of
single-inheritance hierarchical categorization as in your post,
using nested Dynamic values rather than nested extensible types.
But with the appropriate language extension for dynamic type class casts,
Dynamic could also be used for single- or multiple-inheritance hierarchies
based on type classes rather than nesting, whereas I don't see any way
to extend the extensible type approach to support multiple-inheritance
hierarchies.

-- 
Fergus Henderson [EMAIL PROTECTED]  |  "I have always known that the pursuit
WWW: http://www.cs.mu.oz.au/~fjh  |  of excellence is a lethal habit"
PGP: finger [EMAIL PROTECTED]| -- the last words of T. S. Garp.






Re: Sets of IOErrors?

1999-09-29 Thread Fergus Henderson

On 28-Sep-1999, George Russell [EMAIL PROTECTED] wrote:
 I must be missing something.  Isn't it blindlingly obvious that
 here SML's exception mechanism is streets ahead of Haskell's?  Please,
 what am I missing?  Is there some lurking type-unsafeness?

SML's exception mechanism essentially forces sequential execution,
and (I think) causes problems for equational reasoning.
Haskell's exception mechanism preserves referential transparency
and gives the compiler more freedom to reorder and/or parallelize code.

 [snip]
  (a) allow throwing exceptions from arbitrary code, not just from within
  the IO monad

 Aaarrgh no.  If you're going to do unsafe operations then be honest about it
 and use IOExts.unsafePerformIO.

Throwing an exception from arbitrary code is no less safe than calling `error'
or executing a case for which no pattern matches.

Allowing exceptions to be thrown from arbitrary code does not violate
referential transparency.  See the paper that Alastair Reid cited.

 Actually I don't often feel the need to do
 this (I don't think there's any example in UniForM).  Exceptions tend to be
 either because of something IOish (file not found), in which case you are already
 doing state, or else because of a bug in the program, in which case "error"
 is probably appropriate.  

There are many common examples where exceptions arise for reasons other
than I/O, for example integer overflow, division by zero, taking the
square root of a negative number, head of an empty list, and so forth.
If we want to be able to write robust programs, then we need to be able
to recover from such errors.  Likewise, if we want to be able to write
efficient programs, then we need to be able to recover from such
errors, because often it is more efficient and/or easier to make the
common case fast and to deal with the rare cases via an exception
handler than to write code which avoids such raising such
errors/exceptions in the first place.

 I suppose the main problem with "error" is that theoretically
 you have to crash out of all enclosing Haskell code.  I don't understand
 enough about the semantics of haskell to know the answer to this question,
 but could you provide a way of wrapping up a value
a - Maybe a
 so that if somewhere during the evaluation of the a, there is an attempt to
 evaluate "error", the result is Nothing (and perhaps an error
 message printed on the screen), otherwise Just (something).
 Would this break the semantics?

Unfortunately yes.  The possibility of infinite loops causes trouble here.
For the details, which are rather subtle, see the paper.

But a function of type `a - IO (Maybe a)' need not suffer from the
same problem.  You can safely throw exceptions from anywhere, so long
as you only catch them from code in the IO Monad.

-- 
Fergus Henderson [EMAIL PROTECTED]  |  "I have always known that the pursuit
WWW: http://www.cs.mu.oz.au/~fjh  |  of excellence is a lethal habit"
PGP: finger [EMAIL PROTECTED]| -- the last words of T. S. Garp.






Re: Sets of IOErrors?

1999-09-29 Thread Marcin 'Qrczak' Kowalczyk

Wed, 29 Sep 1999 11:43:06 +0200, George Russell [EMAIL PROTECTED] pisze:

 When that happens in my code it counts as a bug!  Therefore error
 is appropriate.  If you are in some larger Haskell universe calling
 component Haskell code it is unfortunate if a single error calls the
 entire universe to collapse, so you do need some way of recovering,

I agree to both of the above.

I only don't like the details about IOError. It's not extensible
and Dynamic is still not nice. I have no idea how to make it
better. Probably some general way of making extensible datatypes.

 but perhaps a function as mentioned of type
a - IO (Maybe a)
 which traps the error might suffice for this case.

How would it work with lazy evaluation? I guess it would simply be
strict in its argument, but what if `a' is a list and an error occurs
during computation of some further element? Probably it would just
fail with _|_.

BTW, can there make sense a universal variant of seq which
recursively seqs components of datatypes? `x == x' would sometimes
work in practice. But maybe it does not make sense theoretically:
does `const [0..]' _contain_ the list so it would be seqed? Maybe the
only sensible generic seq just evaluates the top constructor. But that
way (Bool,Bool) is not "isomorphic" to a four-valued enumeration wrt
seq effect. There are strictness annotations in datatypes, I think
they create isomorphic types, but they create _new_ types: a list
should not be strict all the times but it could make sense to catch
the errors inside the elements when needed. Hmm, a class SuperSeq,
probably automatically derivable? I'm confused. And I'm not sure if
it would be useful at all.

-- 
 __("Marcin Kowalczyk * [EMAIL PROTECTED] http://kki.net.pl/qrczak/
 \__/  GCS/M d- s+:-- a22 C++$ UL++$ P+++ L++$ E-
  ^^W++ N+++ o? K? w(---) O? M- V? PS-- PE++ Y? PGP-+ t
QRCZAK  5? X- R tv-- b+++ DI D- G+ e h! r--%++ y-







Re: Sets of IOErrors?

1999-09-29 Thread Marcin 'Qrczak' Kowalczyk

Thu, 30 Sep 1999 02:08:23 +1000, Fergus Henderson [EMAIL PROTECTED] pisze:

  I only don't like the details about IOError. It's not extensible
  and Dynamic is still not nice. I have no idea how to make it
  better. Probably some general way of making extensible datatypes.
 
 Could you explain what you don't like about Dynamic?

The implementation relies on mkTyCon used in the top level definition;
no referential transparency. Fixing it would begin to rely on manual
invention of unique names. This could fail when the same type name
is used in different modules.

One must know the exact type inside to do anything with it. One cannot
make a singleton list of the value inside Dynamic and put the result
into Dynamic without knowing its type. One cannot declare that all
values in a particular Dynamic are in some class and apply methods
of that class to them without knowing their types.

Errors in describing the types will result in dangerous behavior of
using some value after unsafeCoercing it to an incorrect type.

One cannot describe more elaborate type constructs, like local
universal quantification. Fortunately they may always be put into
separately named datatype, it's not that bad.

At last, there is this explicit Typeable class. Making its instance
is a non-creative technical issue.

Disclaimer: I have not used Dynamic in practice. Maybe it is more
useful than ugly. But I think that most uses of Dynamic are symptoms
of some lacking capabilities in the type system.

-- 
 __("Marcin Kowalczyk * [EMAIL PROTECTED] http://kki.net.pl/qrczak/
 \__/  GCS/M d- s+:-- a22 C++$ UL++$ P+++ L++$ E-
  ^^W++ N+++ o? K? w(---) O? M- V? PS-- PE++ Y? PGP-+ t
QRCZAK  5? X- R tv-- b+++ DI D- G+ e h! r--%++ y-







Re: Sets of IOErrors?

1999-09-29 Thread George Russell

Fergus Henderson wrote:
[snip]
 So why limit expressiveness by providing only the former?
Why indeed?  You are right.  I hadn't realised that
   a - IO (Maybe a)
would still suffer from non-determinism.
(Because if you have 
   x = error "foo" + _|_
   it may cause a return of Nothing or else no return at all.)
So there is no reason for not going the whole way and letting
the caller inspect the contents of the exception.






Re: Sets of IOErrors?

1999-09-29 Thread R.S. Nikhil

[ Apologies that this message is not about Haskell,
  but it is about interesting use of language! ]

Amazingly, Perec's book has been translated into English,
by Gilbert Adair, completely maintaining it's "e-less"
constraint!  The title of the English translation is
"A Void" (the French title would translate as
"The Disappearance", but that contains e's).

It's a fantastic book!  I highly recommend it.

Nikhil

 -Original Message-
 From: Jan Skibinski [mailto:[EMAIL PROTECTED]]
 Sent: Wednesday, September 29, 1999 10:06 AM
 Cc: [EMAIL PROTECTED]
 Subject: Re: Sets of IOErrors?
 
   ... 
 Regardless of all sorts of constraints, Haskell has achieved
   a lot in its current form. Working with restrictions
   can be fun and intellectually stimulating but nevertheless
   it can be sometimes frustrating. It's like writing a book
   without using one of the letters of the alphabet, which
   can be really challenging if you choose not to use the
   most frequent vowel, as "e" in English. (*)
 
   ...
 (*) ...
   - An excentric novel "La disparition" by French writer
 Georges Perec, written in French (again without letter "e")
 in 1969. This is a 26-volumed book (corresponding
 to the fact that there are 26 letters of alphabet),
 with volume 5  missing.






Re: Sets of IOErrors?

1999-09-28 Thread Alastair Reid


 On 08-Sep-1999, Alastair Reid [EMAIL PROTECTED] wrote:
  What
  I'd like (in some future version of Haskell) is an IOError constructor
  which lets me merge two IOErrors together and appropriate operations
  to test for it and, perhaps, take it apart:

Fergus Henderson [EMAIL PROTECTED] replied:
 What existing functions for testing IOErrors?
 Apart from the Eq and Show classes, Haskell 98 doesn't define any, AFAIK.

The IO library defines these functions.
(http://haskell.cs.yale.edu/onlinelibrary/io.html)

 isAlreadyExistsError  :: IOError - Bool
 isDoesNotExistError   :: IOError - Bool
 isAlreadyInUseError   :: IOError - Bool
 isFullError   :: IOError - Bool
 isEOFError:: IOError - Bool
 isIllegalOperation:: IOError - Bool
 isPermissionError :: IOError - Bool
 isUserError   :: IOError - Bool
 ioeGetErrorString :: IOError - String
 ioeGetHandle  :: IOError - Maybe Handle
 ioeGetFileName:: IOError - Maybe FilePath

The idea of these functions is to make use of the type abstract and,
hence, simplify extension of the type.  (I'm not sure it achieves this
because existing code that carefully checks for the above errors would
probably break if we added a new kind of error.)

 If you're suggesting that Eq or Show be undefined for IOErrors that
 represent sets of exceptions, then I would have to disagree...

No problem with Show - I use it all the time.
I think having and using Eq is ok (though it defeats whatever
abstraction the above operations provide).  Obviously we'd want to add
an "elem"-like function as well if we have sets of exceptions.

I was going to suggest that we redefine isAlreadyExistsError and
friends to return true if the associated error is a member of the set.
But if we do this, what do we do with ioeGetErrorString and friends?

 The exception handling in Haskell 98 needs substantial work, IMHO.

I'd certainly agree with that.  My suggestion was meant as a minimal
change to what is already there.

 IMHO Haskell 200X should pick up the Hugs/ghc extensions related to
 exception handling, or something along those lines, in particular:
 (a) allow throwing exceptions from arbitrary code, not just from within
 the IO monad

Fergus and I are in complete agreement here - but then we are
coauthors on a paper[1] that describes how to do it :-) I think this
is quite a minor change - but very, very important if you're trying
to do real things with Haskell.

 (b) allow throwing and catching of dynamically typed values,
 e.g. using an interface like the Hugs/ghc Dynamic library

Despite having written a good deal of the Hugs-GHC Dynamic library[2],
I'm wary of making it part of the standard because it is limited to
handling monomorphic values only: no polymorphism, no overloading.

I'm also a little leery of the lack of structure that would result
from using dynamic typing to provide extensibility.  The hierarchial
organisation of exceptions in Java and other OO languages seems to be
a good match to the task.  (Though, again, how does this interact
with having sets of errors?)

It is probably possible to encode such a hierarchy using Haskell's
type classes but I worry that the lack of overloading in the present
Dynamic library would prevent us from combining the two.  (Anyone care
to prove me wrong on this claim?)


--
Alastair Reid[EMAIL PROTECTED]http://www2.cs.utah.edu/~reid/


[1] http://www2.cs.utah.edu/~reid/except-pldi.ps.gz
@inproceedings{ReidA:PLDI99
,author="S.L. {Peyton Jones} and A. Reid and Tony Hoare and  Simon Marlow and Fergus 
Henderson"
,title="A semantics for imprecise exceptions"
,booktitle = "Programming Languages Design and Implementation (PLDI'99)"
,organization = "ACM press"
,year = "1999"
,month ="May"
,pages="25-36"
,abstract="
Some modern superscalar microprocessors provide only imprecise
exceptions. That is, they do not guarantee to report the same
exception that would be encountered by a straightforward
sequential execution of the program. In exchange, the offer
increased performance or decreased area (which amount to much the
same thing).  This performance/precision tradeoff has not so far
been explored at the programming langauge level. In this paper we
propose a design for imprecise exceptions in the lazy functional
programming language Haskell. We discuss various simpler designs,
and conclude that imprecision is essential if the language is
still to enjoy its current rich algebra of transformations. We
sketch a precise semantics for the language extended with
exceptions.  From the functional programming point of view, the
paper shows how to extend Haskell with exceptions without
crippling the language or its compilers. From the point of view
of the wider programming language community, we pose the question
of whether precision and performance can be traded off in other
languages too.
"
}

[2] http://haskell.cs.yale.edu/ghc/docs/latest/libraries/libs.html






Re: Sets of IOErrors?

1999-09-28 Thread Alastair Reid


   (b) allow throwing and catching of dynamically typed values,
   e.g. using an interface like the Hugs/ghc Dynamic library

[discussion of Dynamic library, etc deleted]

[The following is a bit of a straw-man: it doesn't quite work but
may have good parts which can be used in other designs.]

(part of) Another approach is to extend Haskell with extensible
datatypes as is done in ML.  This is what I did in the late,
unlamented GreenCard 1 - you could define a new IOError constructor
whenever you wanted.  

This was easy to do because GreenCard 1's implementation exploited the
fact that it had full access to Hugs' internal data structures.  When
we moved onto GreenCard 2 and had to add GHC support, this was no
longer such an easy choice and we reluctantly switched to encoding
errors as strings.

If Haskell supported extensible datatypes, it would be easy to define a
hierarchy of exception values.  For example, the attached pseudocode
creates a hierarchy like this:

  IOError
Win32Error
  GDIError
BadRegion
BadBrush
PosixError
  ENOTDIR
  ENAMETOOLONG
  EINTR
UserError
AlreadyExists

Disadvantages of this approach include:

o Most Haskell features can be described as "just syntactic sugar"
  - it's hard to do this here.

o It's hard to write total functions over extensible datatypes (eg
  try writing a Show function for the attached definition of IOError).

o This is the only compelling use for extensible datatypes - wouldn't
  it be better to support exception handling more directly?



--
Alastair Reid[EMAIL PROTECTED]http://www2.cs.utah.edu/~reid/


module IO(...) where
  ...
  -- define the type
  extensible  IOError :: *  
  
  -- define some constructors
  constructor UserError :: String   - IOError  
  constructor AlreadyExists :: FilePath - IOError
  

module Posix(...) where   -- Posix Stuff

  import IO(IOError)

  -- define a new hierarchy of errors
  extensible  PosixError :: *

  -- link the new hierarchy into IOError
  constructor PosixError :: PosixError - IOError

  -- define some Posix errors
  constructor ENOTDIR  :: FilePath - PosixError
  constructor ENAMETOOLONG :: FilePath - PosixError
  constructor EINTR:: PosixError
  ...


module Win32(...) where   -- Windows 95/98/NT stuff

  import IO(IOError)

  -- define a new hierarchy of errors
  extensible  Win32Error :: *

  -- link the new hierarchy into IOError
  constructor Win32Error :: Win32Error - IOError



module Win32GDI(...) where   -- Windows graphics primitives

  import Win32(Win32Error)

  -- define a new hierarchy of errors
  extensible  GDIError :: *

  -- link the new hierarchy into IOError
  constructor GDIError :: GDIError - Win32Error

  -- define some GDI errors
  constructor BadRegion :: HREGION - GDIError
  constructor BadBrush  :: HBRUSH  - GDIError
  ...