[Haskell-cafe] When to use fancy types [Re: NumberTheory library]

Jan-Willem Maessen jmaessen at alum.mit.edu
Thu May 12 10:45:18 EDT 2005


On May 10, 2005, at 4:14 AM, Bo Herlin wrote:

> > Well, part of what I was doing was experimenting with what a library 
> like
> > this should look like, even more than what it should do.  For some 
> reason,
> > I kind of like writing this:
> >
> >     *Math.Prime> is Prime 42
> >     False
> >
> > instead of this:
> >
> >     *Math.Prime> isPrime 42
> >     False
>
> Great! I like this a LOT.

Why not use a function?

What's wrong with a function?

There no need to go leaping for a multiparameter type class with a 
functional dependency!  Just use a function.

[With apologies to John Cleese]

In all seriousness, I loathe this style.  Let me tell you why:

* We are introducing types whose only purpose is to stand for a single 
function.

* Declaring a property used to take one line---a function declaration.  
Now it takes a minimum of three:
   - a bogus type declaration for Primes
   - an instance declaration
   - the actual declaration for "is".

* The use of multiparameter type classes leads to relatively more 
obscure error messages and clunky type signatures with bogus type 
parameters.

* It's not Haskell 98, and an acceptable (or even preferable) solution 
exists which is.

* There's no equivalent of lambda here---we can't write anonymous 
properties.  I list this last, as some may consider it a disadvantage.


When using fancy type-system footwork, I suggest the following 
questions (which I ask myself, too):

* Can I replace one or more parameters to my methods with a 
suitably-typed call to "undefined"?  This often means I'm being to 
clever for my own good.  Perhaps that argument could be eg. a phantom 
parameter of another type.

* What would happen if I used a record instead of a class declaration?  
The result might look pretty similar on the page, but it might be H98.  
If the class has 0 or 1 method, you don't even need a record---you can 
pass things directly.

* Could I use a newtype rather than a separate type parameter?  
Sometimes this is acceptable, sometimes it's better, and sometimes (in 
the case of the NumberTheory library, I suspect) it's not what you 
actually want.

* How much worse would it look if I just used H98?  Sometimes it won't 
be possible at all.  Sometimes it just requires a change of perspective 
to make it look very pretty.  And often a bunch of fancy footwork at 
the type level leads to a solution that I didn't anticipate---and which 
fits nicely in H98.


I also have an informal mental hierarchy of complexity of 
types---though others may find this more controversial:
   * Simple algebraic types
   * H98 type classes
   * Fancier instance heads (but still single-parameter, non-overlapping)
   * Existential and local universal quantification
   * GADTs (I'm still uncertain about this judgement, but they seem to 
be less troublesome than...)
   * Multiparameter type classes


-Jan-Willem Maessen



More information about the Haskell-Cafe mailing list