"class []" proposal Re: [Haskell-cafe] One thought: Num to 0as ? to list?

Malcolm Wallace Malcolm.Wallace at cs.york.ac.uk
Wed Aug 23 08:28:57 EDT 2006

> > it's because you not programmed a lot with type classes. if you
> > start, you will soon realize that type signatures with classes are
> > just unreadable. just look at sources of my streams library
>     copyStream :: (BlockStream h1, BlockStream h2, Integral size)
>                    => h1 -> h2 -> size -> IO ()

I know this is probably just a personal preference, but I have to say
that this syntax (the canonical Haskell'98 one) is by far the most
readable and instantly clear of any of the alternatives that have been
suggested in this thread:

    copyStream :: BlockStream* -> BlockStream** -> Integral -> IO ()

Here you have invented a new notation for type variables (* and **),
when we already have a perfectly good one.

    copyToMemoryStream :: BlockStream -> MemoryStream -> Integral -> IO ()

Whereas here, the lack of any type variable means I am no longer aware
that overloading is going on.  This is likely to discourage the reuse of
this code fragment, rather than encourage it.

    copyStream :: {BlockStream} h1 -> {BlockStream} h2
                  -> {Integral} size -> IO ()

What is gained by attaching the constraints inline with the type
variables?  If the type variable occurs more than once, which occurrence
should I attach the constraint to?  What if I attach different
constraints to different occurrences of the same variable?  (Obviously
the union is intended, but writing constraints in several different
locations would be highly confusing).  But at least there is a syntactic
marker ({}) that overloading is happening.

    copyStream :: {BlockStream} -> {BlockStream} -> {Integral} -> IO ()

Again, omitting type variables means that the possible mental confusion
over whether the two {BlockStream} constraints apply to the same
implicit variable or to different ones is unpleasant.  Better to be
fully explicit, after all, it only takes one extra character to name the

>     foo :: Collection c a => a -> c
> === foo :: {Collection c} a -> c
>     foo :: Collection c a => c -> c
> === foo :: {Collection * a} c -> c
>     forall a. Num a => (forall b. (Coll b a, Ord b) => b a -> ()) -> ()
> === (forall b. {Coll * a, Ord}b    {Num}a   -> ())    ->   ()
> === forall a. (forall b. ({Coll * a, Ord} b) ({Num} a) -> ()) -> ()

The lengths people will go to in making things difficult for the reader,
just to save a few characters is truly amazing.  Remember, the code will
be read many more times than it is written.  IMHO, the various proposed
sugar adds nothing helpful, and just muddies understanding.


More information about the Haskell-Cafe mailing list