Well, the cat has been skinned and boned, but I think I see a
shread of meat or two that hasn't been picked over yet...

On Thu, 10 Jun 1999, Frank A. Christoph wrote:

[some attributions missing...I hope you know who you are]

[big snip, about the fact that Haskell programs can be quite brief]

> Third, it is actually quite common in Haskell (in my experience at
> least) to use very non-descriptive names for local variables if the
> definition is short.  I think it helps readability because the program
> fragment is shorter as a result, and it is easier to see the
> relationship between all the elements. For example, compare:
> 
>   map :: (a -> b) -> [a] -> [b]
>   map f [] = []
>   map f (x:xs) = (f x) : map f xs
> 
>   transformListElems :: (elem -> elem') -> List elem -> List elem'
>   transformListElems transform Nil = Nil
>   transformListElems transform (Cons elem elemRest) =
>     Cons (transform elem) (transformListElems transform elemRest)

Well, the second version does more than just use descriptive variable
names (and some not very descriptive, for that matter).  It also spells
out constructors, has an especially long-winded function name, and uses
one name for both a type variable and an argument (and a "primed" version
for a second type variable).  I would prefer to compare with:

   map :: (atype -> btype) -> [atype] -> [btype]
   map transform [] = []
   map transform (head:rest) = (transform head) : map transform rest

Now, I wouldn't necessarily prefer that form to the "canonical" one, but I
think this is because the canonical one *is* canonical.  That is, there
are some additional Haskell conventions that really are not spelled out as
well as they might be.

You point out that short variable names keep code segments short, but my
take on the why Haskell seems to "prefer" short names in many situations
is that they are easier to think of as being *generic*.  (Intuitively,
when you make a concept something more specific, it tends to get a longer
name.)

So, the name of a type is always at least a full word, as are the names of
specific functions.  But type variables are almost always single
characters, and distinct from the names of any type.  Conventionally, they
are also usually "a", "b", and "c", although "m" is for monad.
Conventionally also, generic function arguments are "f" and "g", the
conventional predicate is "p". Generic arguments are "x" and "y" (or "xs"
and "ys" if they are lists); arguments with specified types are usually
the first letter of their type name (e.g., "c" for Char, "i" for an Int;
"n" and "m" are indices)... that covers most of it, I think.

I think most of the Haskell code I've ever seen that *wasn't* written by
me follow these conventions pretty closely.  But the strange thing is...I
haven't found a prominent place on, e.g., the Haskell home page where this
is spelled out. (Please tell me if I'm missing anything obvious.) In a
way, I guess this is trivial, but I know from hard experience it can often
take a long time to become completely aware of trivial things.

It's amusing, actually.  Haskell basically defines your indentation for
you, these conventions give you all your variable names, static
type-checking almost ensures program correctness...I guess students taking
their first Haskell course should all get As and all produce identical
code on their homework assignments. :-)

> Of course, for more involved definitions, it is better to use 
> descriptive names.

Well, for more specific definitions, anyway.  If I've got the style right.

jking




Reply via email to