+mkTyConApp :: TyCon -> [Type] -> Type
+mkTyConApp tycon tys
+ | isFunTyCon tycon && length tys == 2
+ = case tys of
+ (ty1:ty2:_) -> FunTy ty1 ty2
+
+ | otherwise
+ = ASSERT(not (isSynTyCon tycon))
+ TyConApp tycon tys
+
+mkTyConTy :: TyCon -> Type
+mkTyConTy tycon = ASSERT( not (isSynTyCon tycon) )
+ TyConApp tycon []
+
+-- splitTyConApp "looks through" synonyms, because they don't
+-- mean a distinct type, but all other type-constructor applications
+-- including functions are returned as Just ..
+
+splitTyConApp_maybe :: Type -> Maybe (TyCon, [Type])
+splitTyConApp_maybe (TyConApp tc tys) = Just (tc, tys)
+splitTyConApp_maybe (FunTy arg res) = Just (funTyCon, [arg,res])
+splitTyConApp_maybe (NoteTy _ ty) = splitTyConApp_maybe ty
+splitTyConApp_maybe other = Nothing
+
+-- splitAlgTyConApp_maybe looks for
+-- *saturated* applications of *algebraic* data types
+-- "Algebraic" => newtype, data type, or dictionary (not function types)
+-- We return the constructors too.
+
+splitAlgTyConApp_maybe :: Type -> Maybe (TyCon, [Type], [DataCon])
+splitAlgTyConApp_maybe (TyConApp tc tys)
+ | isAlgTyCon tc &&
+ tyConArity tc == length tys = Just (tc, tys, tyConDataCons tc)
+splitAlgTyConApp_maybe (NoteTy _ ty) = splitAlgTyConApp_maybe ty
+splitAlgTyConApp_maybe other = Nothing
+
+splitAlgTyConApp :: Type -> (TyCon, [Type], [DataCon])
+ -- Here the "algebraic" property is an *assertion*
+splitAlgTyConApp (TyConApp tc tys) = ASSERT( isAlgTyCon tc && tyConArity tc == length tys )
+ (tc, tys, tyConDataCons tc)
+splitAlgTyConApp (NoteTy _ ty) = splitAlgTyConApp ty
+\end{code}
+
+"Dictionary" types are just ordinary data types, but you can
+tell from the type constructor whether it's a dictionary or not.