There are too many error handling conventions used in library code!

Udo Stenzel u.stenzel at web.de
Sun Mar 11 20:35:49 EDT 2007


Eric Kidd wrote:
> 1. Network.URI.parseURI returns (Maybe URI).
> 2. Network.HTTP.simpleHTTP returns (IO (Result Request)), which is basically a
> broken version of (IO (Either ConnError Request)).
> 3. Parsec returns (Either ParseError a)
> 
> So there's no hope that I can write anything like:
> 
>   do uri <- parseURI uriStr
>      doc <- evenSimplerHTTP uri
>      parsed <- parse grammar uriStr doc

do uri    <- maybe (fail "broken uri") return  $  parseURI uriStr
   doc    <- either throwDyn return           =<< evenSimplerHTTP uri
   parsed <- either throwDyn return            $  parse grammar uriStr doc


...untested of course, and only intended to show the principle.  You may
not want to "throwDyn" everything, instead you might use a suitable
MonadError or want to "show" those errors that aren't already strings,
etc.  You get a bit of noise, but also flexibility.  Am I the only one
who doesn't see a problem here?


> c) Provide a unified way to deal with the error ADTs defined by libraries, e.g.,
> ConnError, ParseError, etc. At the moment, this is pretty non-trivial: You need
> to either smash everything down to a string, or use something hairy, such as
> '(Error e, Typeable e) => Either e a'. This is where novice Haskell programmers
> are most likely to wind up in trouble.

Err, no, you either wrap everything up in a custom type

data AllSortsOfErrors = WhoKnows | DescribedBy String 
                      | ConnError ConnError | ParseError ParseError
		      | ...

or you use Dynamic, which essentially is such a union containing
everything.  Of course, if all you're gonna do anyway is print a message
and go on with your business, then smashing everything down to strings
is exactly what the doctor ordered anyway.


> d) Provide a way to deal with errors in mixed functional/IO-based code. It would
> be especially nice to have lifting functions that converted Either/ErrorT-based
> errors into the exceptions used in the IO monad.

See above.  Of course, you could give "either throwDyn return" a name,
I'm not sure it buys you that much, though.


> One point I made earlier about throwDyn: Out of the 8 error-handling strategies,
> throwDyn is the only one that can mix ConnError and ParseError in a reasonably
> seemless fashion.

...but only if you're in IO code anyway and only if handling the
exception will also be done in IO code.  In all other cases, the most
well known mix of ConnError and ParseError is called "Either ConnError
ParseError".

 
> > can we make precise recommendations about which error strategies to use?

How about "don't forget about algebraic data types"?  Other than that,
make liberal use of MonadError.  Given enough polymorphism, a lot of
the heavy lifting simply vanishes.


-Udo
-- 
"Poor man... he was like an employee to me."
	-- The police commisioner on "Sledge Hammer" laments
	   the death of his bodyguard
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
Url : http://www.haskell.org/pipermail/libraries/attachments/20070312/91586a5e/attachment.bin


More information about the Libraries mailing list