This recursive definition of T fails to type-check.
class C a where
type T a :: Type
newtype Compose (f :: Type -> Type) (g :: Type -> Type) (a :: Type) = Compose {getCompose :: f (g a)}
instance C (Maybe a) where
type T (Maybe a) = NP (Compose T Identity) '[a]
Specific error:
• The associated type family ‘T’ should have 1 argument, but has been given none
• In the type instance declaration for ‘T’
In the instance declaration for ‘C (Maybe a)’
|
32 | type T (Maybe a) = NP (Compose T Identity) '[a]
| ^
- Why is GHC unable to do this?
- Is there a workaround?
The real class/instance looks like this:
instance Ema (MultiSite models) where
type RouteFor (MultiSite models) = NP (Compose RouteFor Site) models
This says that "the route for a multisite is an n-ary product of the routes for the individual sites", hence RouteFor has to be defined recursively.
Type families are unmatchable and must be fully saturated. This means they can not be passed partially applied as an argument. This is basically what the error message says
At the present time this is not distinguished at the kind level (see Unsaturated type families proposal) but there is a very clear distinction within GHC.
According to
:kindbothTandIdentityhave the same kind while in realityIdentityis Matchable andTis Unmatchable:Because the arguments of
ComposeareType -> @M Typeyou cannot pass an unmatchable type family. The type language is first order! (Higher-Order Type-Level Programming in Haskell) and there is no way to defineComposethat accepts an unmatchable function at the moment.If you compare the kind of the slightly modified
T1andT2, the first one is unmatchable in both arguments while the second is matchable in its second argumentA possibility is to wrap it in a (matchable) newtype