[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