[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