{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS -Wall #-}
module Main where

import GHC.Generics
import Data.Kind (Type)
import GHC.TypeLits (Symbol)

-- Helper stuff
type family Append a b where
  Append '[] ys = ys
  Append (x : xs) ys = x : Append xs ys

-- 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 -> [Symbol]
type EnumValues a = GEnumValues (Rep a)

type family GEnumValues a where
  GEnumValues (M1 D _ b) = GEnumValues b
  GEnumValues (M1 C ('MetaCons name _ _) U1) = '[name]
  -- this nested type family application needs UndecidableInstances
  GEnumValues (a :+: b) = Append (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 '[] a
  (:>) :: a -> OneForEach l a -> OneForEach (t : l) 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