On Mar 12, 2008, at 6:34 AM, Brandon S. Allbery KF8NH wrote:


On Mar 11, 2008, at 14:27 , Donn Cave wrote:
    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.

You might want to think about the monadic use of Maybe/Either (or more generally MonadError), which abstracts away the checking and tracking into (>>=). The error handler is then at the point where values are injected into / retrieved from the monadic exception, similar to catch (...).

Sure.  It isn't a lot of code, so I subjected it to Either-ization
as an experiment, and I did indeed take the monad procedural route.
The example function above became

   readLDAPMessage s = do
       [(_, msgID), (tag, body)] <- berList s >>= exactLen 2
       i <- berInt msgID
       r <- readResponse tag body
       return (LDAPMessage i r)

... and the end result, applying this style across a number of
related functions, was no more than half again as much code,
and I guess not severely unreadable.  Maybe it depends on whether
a procedural style suits you.  There may be clever ways to torture
this logic into an even smaller format, but since the original
is the clearest expression of the protocol and its caller is
almost guaranteed to have an exception handler anyway -- in my
opinion, it was a silly exercise, I'll throw the code away.

The Either version forces strict evaluation, true?  Let's say for
some reason the caller actually uses only the first part, the LDAP
message ID, then we don't really need to validate and decode the
whole message, but if I were to Either-ize it, then it has to go
the whole distance before we know it's Right and not Left?  And
likewise for every value of every attribute in the message.

What I naively picture as the next step, where pure code can
handle exceptions, is an _implicit_ evaluation monad like Either.
Pattern matches then throw exceptions in the sense described in
Control.Monad.Error, which may be caught in pure code by optionally
making the monadic type explicit, or otherwise are converted to
exceptions in the sense of Control.Exception and caught in the
IO monad.  I suppose this would not force evaluation, because it's
fine grained - I don't fold (Right i) and (Right r) into
(Right (LDAPMessage i r)), etc., but rather you may encounter
a (Left _) anywhere in there.  At least this would let us rationalize
the use of 'exception' with two radically different meanings between
Control.Monad.Error and Control.Exception.

        Donn Cave, [EMAIL PROTECTED]
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to