    {-# LANGUAGE FlexibleContexts #-}
    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE ScopedTypeVariables #-}
    {-# LANGUAGE TypeOperators #-}
    {-# LANGUAGE TypeSynonymInstances #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Generics.Deriving.ConNames
    -- Copyright   :  (c) 2012 University of Oxford
    -- License     :  BSD3
    --
    -- Maintainer  :  generics@haskell.org
    -- Stability   :  experimental
    -- Portability :  non-portable
    --
    -- Summary: Return the name of all the constructors of a type.
    --
    -----------------------------------------------------------------------------

    module Generics.Deriving.ConNames (

        -- * Functionality for retrieving the names of the possible contructors
        --   of a type or the constructor name of a given value
        ConNames(..), conNames, conNameOf

      ) where

    import Generics.Deriving.Base

    class ConNames f where
        gconNames  :: f a -> [String]
        gconNameOf :: f a -> String

    instance (ConNames f, ConNames g) => ConNames (f :+: g) where
        gconNames (_ :: (f :+: g) a) = gconNames (undefined :: f a) ++
                                       gconNames (undefined :: g a)

        gconNameOf (L1 x) = gconNameOf x
        gconNameOf (R1 x) = gconNameOf x

    instance (ConNames f) => ConNames (D1 c f) where
        gconNames (_ :: (D1 c f) a) = gconNames (undefined :: f a)

        gconNameOf (M1 x) = gconNameOf x

    instance (Constructor c) => ConNames (C1 c f) where
        gconNames x = [conName x]

        gconNameOf x = conName x

    -- We should never need any other instances.

    -- | Return the name of all the constructors of the type of the given term.
    conNames :: (Generic a, ConNames (Rep a)) => a -> [String]
    conNames x = gconNames (undefined `asTypeOf` (from x))

    -- | Return the name of the constructor of the given term
    conNameOf :: (ConNames (Rep a), Generic a) => a -> String
    conNameOf x = gconNameOf (from x)