-- Kinds are "types of types"
-- Int :: Type (Type is also written *)
-- Maybe :: Type -> Type
-- Either :: Type -> Type -> Type
-- Either String :: Type -> Type
-- StateT :: Type -> (Type -> Type) -> Type -> Type
-- Functor :: (Type -> Type) -> Constraint
{-# LANGUAGE KindSignatures #-}
import Data.Kind (Type)
-- Higher-kinded type parameter: f has kind Type -> Type
data Wrapper (f :: Type -> Type) a = Wrapper (f a)
newtype Compose f g a = Compose (f (g a))
instance (Functor f, Functor g) => Functor (Compose f g) where
fmap h (Compose x) = Compose (fmap (fmap h) x)
-- "Higher-kinded data" pattern: one record definition, different wrappers
data PersonF f = PersonF {pName :: f String, pAge :: f Int}
type Person = PersonF Identity -- import Data.Functor.Identity
type PartialPerson = PersonF Maybe -- e.g., form input where fields may be missing
validatePerson :: PartialPerson -> Maybe Person
validatePerson (PersonF n a) = PersonF <$> (Identity <$> n) <*> (Identity <$> a)