{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TypeData #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} {-# OPTIONS -Wall #-} module Main where import GHC.Generics import Data.Kind (Type) -- Helper stuff type data Nat = Z | Su Nat type family Add a b where Add Z m = m Add (Su n) m = Su (Add n m) -- Type-level list of the constructor names (actually we don't even need the -- names to do the trick below, but why not collect them, yolo) type EnumValues :: Type -> Nat type EnumValues a = GEnumValues (Rep a) type family GEnumValues a where GEnumValues (M1 D _ b) = GEnumValues b GEnumValues (M1 C ('MetaCons name _ _) U1) = Su Z -- this nested type family application needs UndecidableInstances GEnumValues (a :+: b) = Add (GEnumValues a) (GEnumValues b) -- One 'a' for each item in the type-level list 'l' (the values in 'l' are -- unused) data OneForEach l a where End :: OneForEach Z a (:>) :: a -> OneForEach n a -> OneForEach (Su n) a infixr :> deriving instance Show a => Show (OneForEach l a) -- Your data types data Test1 = ONE | TWO | THREE deriving (Show, Generic) data Test2 = FOUR | FIVE | SIX deriving (Show, Generic) type AlertMap t = OneForEach (EnumValues t) String x :: AlertMap Test1 x = "eins" :> "zwei" :> "drei" :> End main :: IO () main = print x