I’ve implemented the numtype-tf library which is in essence numtype using type families (hence the “-tf”) instead of functional dependencies. Some of my design decisions are slightly different (beside the choice of type system extension), e.g. the representation of negative integers is different and the PosType and NegType classes have been dropped in numtype-tf. The haddocks have also been improved a little.

A feature of the functionally dependent numtype that I was unable to reproduce with type families is ”mutual dependencies”, used in the Sum and Div type classes of numtype. Here is an example of type signatures (instances omitted) and ghci usage:

In order for the latter to compute we must assist the type checker by being explicit about the type of a0, i.e. pos3 - pos5 :: Neg2, which largely defeats the purpose of type level arithmetic. Instead two type families are used in numtype-tf:

This works OK but the lack och mutual dependencies in type families restricts what I will losely refer to as “type inference back tracking”. This may or may not be a significant drawback compared to fundep numtype depending on the use case.

If you are interested in comparing code written with type families to code written with functional dependencies take a look at the respective modules on Github: Numeric.NumType.TF vs. Numeric.NumType.

The next step is to reimplement dimensional as dimensional-tf in order to exercise numtype-tf and better understand the impact of the differences with respect to numtype. I am also looking forward to playing with GHC.TypeNats in GHC 7.4.

2 comments:

This should give you back “type inference back tracking”, if I understand what you mean by that.

(Making Sum definitionally commutative by including both Sub c a ~ b and Sub c b ~ a might be too ambitious, though—you might have to discard the latter, or split subtraction into left and right subtraction.)