[Haskell-cafe] Haskell and the Software design process

wren ng thornton wren at freegeek.org
Sun May 9 04:04:39 EDT 2010


Gregory Crosswhite wrote:
> Yes, but I think that it is also important to distinguish between cases
> where an error is expected to be able to occur at runtime, and cases
> where an error could only occur at runtime *if the programmer screwed up*.

Well sure, but how can you demonstrate that you (the programmer) haven't 
screwed up? That's the point that I'm most interested in.

Certainly there is a difference between exceptional behavior at runtime 
(e.g., due to malformed inputs) vs programming errors. We can't stop the 
former without broadening the scope of the typesystem to include runtime 
inputs; but we can, at least idealistically, stop the latter. While 
complex invariants require full dependent types to capture, there are a 
surprising number of invariants that Haskell's type system can already 
capture (even without GADTs!).


> If you structure your code to preserve and rely on the invariant that a
> given list has at least two elements, then it makes sense to call secondElement
> because if the list doesn't have two elements then you screwed up.  Furthermore,
> there is no way to recover from such an error because you don't necessarily
> know where the invariant was broken because if you did you would have
> expected the possibility and already fixed it.

If you're structuring your code with that invariant, then why aren't you 
using the correct type?

     data AtLeastTwo a = ALT a a [a]

If your response is that you use too many of the standard list 
functions, then write a module with ALT versions (because evidently you 
need one). If your response is that you convert between lists and ALT 
too often, then you probably need to restructure the code. At the very 
least you should be using a newtype and smart constructors, so that you 
can actually prove your invariant whenever necessary:

     newtype AtLeastTwo a = Hidden_ALT [a]
     altEnd   :: a -> a -> AtLeastTwo a
     altCons  :: a -> AtLeastTwo a -> AtLeastTwo a
     altList  :: a -> a -> [a] -> AtLeastTwo a
     fromList :: [a] -> Maybe (AtLeastTwo a)
     toList   :: AtLeastTwo a -> [a]

Without smart constructors or an ADT to enforce your invariants, why 
should you be convinced that you (the programmer) haven't messed up? The 
cheap and easy access to ADTs is one of the greatest benefits of Haskell 
over mainstream languages, don't fear them.

-- 
Live well,
~wren


More information about the Haskell-Cafe mailing list