Now that we have injective type families, is there any remaining use case for using data families over type families?
Looking at past StackOverflow questions about d
type family T a = r | r -> a
data family D a
An injective type family T
satisfies the injectivity axiom
if
T a ~ T b
thena ~ b
But a data family satisfies the much stronger generativity axiom
if
D a ~ g b
thenD ~ g
anda ~ b
(If you like: Because the instances of D
define new types that are different from any existing types.)
In fact D
itself is a legitimate type in the type system, unlike a type family like T
, which can only ever appear in a fully saturated application like T a
. This means
D
can be the argument to another type constructor, like MaybeT D
. (MaybeT T
is illegal.)
You can define instances for D
, like instance Functor D
. (You can't define instances for a type family Functor T
, and it would be unusable anyway because instance selection for, e.g., map :: Functor f => (a -> b) -> f a -> f b
relies on the fact that from the type f a
you can determine both f
and a
; for this to work f
cannot be allowed to vary over type families, even injective ones.)