+ rule args = (TyConApp tycon tys, substTyWith tvs_eta tys rhs_eta, rest)
+ where
+ tys = take co_con_arity args
+ rest = drop co_con_arity args
+
+ -- if the rhs_ty is a type application and it has a tail equal to a tail
+ -- of the tvs, then we eta-contract the type of the coercion
+ rhs_args = let (ty, ty_args) = splitAppTys rhs_ty in ty_args
+
+ n_eta_tys = count_eta (reverse rhs_args) (reverse tvs)
+
+ count_eta ((TyVarTy tv):rest_ty) (tv':rest_tv)
+ | tv == tv' && (not $ any (elemVarSet tv . tyVarsOfType) rest_ty)
+ -- if the last types are the same, and not free anywhere else
+ -- then eta contract
+ = 1 + (count_eta rest_ty rest_tv)
+ | otherwise -- don't
+ = 0
+ count_eta _ _ = 0
+
+
+ eqVar (TyVarTy tv) tv' = tv == tv'
+ eqVar _ _ = False
+
+ co_con_arity = (tyConArity tycon) - n_eta_tys
+
+ tvs_eta = (reverse (drop n_eta_tys (reverse tvs)))
+
+ rhs_eta
+ | (ty, ty_args) <- splitAppTys rhs_ty
+ = mkAppTys ty (reverse (drop n_eta_tys (reverse ty_args)))
+
+-- Coercion identifying a data/newtype representation type and its family
+-- instance. It has the form `Co tvs :: F ts :=: R tvs', where `Co' is the
+-- coercion tycon built here, `F' the family tycon and `R' the (derived)
+-- representation tycon.
+--
+mkDataInstCoercion :: Name -- unique name for the coercion tycon
+ -> [TyVar] -- type parameters of the coercion (`tvs')
+ -> TyCon -- family tycon (`F')
+ -> [Type] -- type instance (`ts')
+ -> TyCon -- representation tycon (`R')
+ -> TyCon -- => coercion tycon (`Co')
+mkDataInstCoercion name tvs family instTys rep_tycon
+ = mkCoercionTyCon name coArity (mkKindingFun rule)
+ where
+ coArity = length tvs
+
+ rule args = (substTyWith tvs tys $ -- with sigma = [tys/tvs],
+ TyConApp family instTys, -- sigma (F ts)
+ TyConApp rep_tycon tys, -- :=: R tys
+ rest) -- surplus arguments
+ where
+ tys = take coArity args
+ rest = drop coArity args