[Haskell-cafe] Exception handling when using STUArray
donn at avvanta.com
Tue Mar 11 14:27:39 EDT 2008
On Mar 10, 2008, at 5:48 PM, Jonathan Cast wrote:
> On 10 Mar 2008, at 12:37 AM, Donn Cave wrote:
>> An exception is, for me, any state that isn't properly accounted
>> for in its
>> immediate context. openFile could return 'Maybe Handle', but it
>> so the context demands a Handle or an exception.
> In the context of this discussion, `Maybe Handle' /is/ an exception
> type, because Maybe is an exception monad. As is IO. This
> distinction is one between an unusual-but-anticipated code path,
> and a case the programmer simply didn't handle at all. The former
> is an exception; the latter is an error.
I am not sure I understand what you're saying. `Error' may be open
to interpretation, but `exception' has a fairly unambiguous technical
meaning in Haskell, a non-local flow of control with associated data
type in Control.Exception. That flow of control involves `exception
handlers', so named in the documentation, so if I install an exception
handler in location that can intercept the exception, then you can't
really say no one handled it, without some violence to the language.
An exception, in the technical sense of the word, really can only be
handled somewhere else, other than the exact location the exception
was thrown, that being the nature and intent of non-local flow of
What I'm trying to bring to this is that if we can let go of our
fastidious notions about Maybe and Either and embrace what appears to
be the reality of exceptions in Haskell that are more or less like other
languages, then we'll be pleased at the improvement in the code.
Here's a function I wrote a couple weeks ago while playing around
with LDAP. I have read this ByteString from a socket, and verified
that it's complete - it's all BER length encoded data, and the string
is of the length specified in its length tag. Now I start breaking
it down, according to my understanding of the Basic Encoding Rules
and LDAP. The `berList' function handles the BER part, and this is
the first LDAP step:
readLDAPMessage s = let [(_, msgID), (tag, body)] = berList s in
LDAPMessage (berInt msgID) (readResponse tag body)
I go on to account for all the LDAP stuff I need in about 60 lines
of that kind of thing, 1/3 of it devoted to declarations of the
data types, and it isn't dense code, it's ... essentially declarative,
in a simple, straightforward way, almost as if I copied it directly
from the RFC.
Is it `total'? No way! To get there, it seems to me I'd have to
double the code, and significantly distract from its real sense.
If there were anything to be gained, sure it's worth the price, but
there isn't! Recall that this data comes from a socket. On the
other end, anyone who cares about survival has an exception handler.
I could gather up layers of Lefts and Rights and return a Left blah,
and it really only adds another failure mode for the caller.
I'm not saying Either is bad - I do use it like this, when it seems
to be called for, but I'm very glad that it isn't the only way to
deal with errors originating in functional code. I had the contrary
impression from a discussion some years back, where I see now in review
I may have conflated what you can't do in Haskell 98, with what you
can't do in pure code for theoretical reasons. (Though I'm not saying
that the argument for the latter was persuasive. I think handing
exceptions in pure code is just the next step.)
Donn Cave, donn at avvanta.com
More information about the Haskell-Cafe