{-# LANGUAGE GADTs, DataKinds, TypeFamilies, UndecidableInstances #-} main = return () data Nat = Z | S Nat data Even (a :: Nat) :: * where ZeroEven :: Even Z NextEven :: Even n -> Even (S (S n)) type family Add (n :: Nat) (m :: Nat) :: Nat type instance Add Z m = m type instance Add (S n) m = S (Add n m) type family Mult (n :: Nat) (m :: Nat) :: Nat type instance Mult Z m = Z type instance Mult (S n) m = Add (Mult n m) n evenPlusEven :: Even n -> Even m -> Even (Add n m) evenPlusEven ZeroEven m = m evenPlusEven (NextEven n) m = NextEven (evenPlusEven n m) evenTimesEven :: Even n -> Even m -> Even (Mult n m) evenTimesEven ZeroEven m = ZeroEven evenTimesEven (NextEven n) m = evenPlusEven (evenTimesEven n m) (evenPlusEven m m)