
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