
Hi Alex, S. Alexander Jacobson wrote:
I guess I'm also not sure what belongs in a GADT and what belongs in a typeclass e.g. here is an Arrow GADT
data Arrow b c where Arr::(b->c) -> Arrow b c Compose::Arrow b c -> Arrow c d -> Arrow b d First::Arrow a b -> Arrow (a,c) (b,c)
When Arrow is defined like this, rather than write instances you just various evaluation functions for the Arrow GADT.
Indeed, there is a free choice (no pun) between this datatype and a class instance. The way I think about it, the datatype 'Arrow' above is the universal/free/(most general) instance of the class 'Arrow'. As you mention, specific instances of the class correspond to evaluation functions on this datatype. (In fact, this datatype presumably is the colimit of all instances of the 'Arrow' class, suitably interpreted as a functor.) In practice, you usually just want an instance; the universal datatype is only an extra layer of indirection. Sometimes however this datatype keeps useful extra information. I have used this approach once to allow algebraic manipulation of some kind of arrows: the GADT constructors make it possible to do pattern matching on the structure of the arrow. This is impossible if your arrow is some opaque function. Regards, Arie