```
-- | Algebraic data type definitions.

-- * Data type definition table
, DataMode   (..)
, DataType   (..)
, DataCtor   (..)

, lookupModeOfDataType)
where
import DDC.Type.Exp
import Data.Map                 (Map)
import qualified Data.Map       as Map
import Data.Maybe

-- | The definition of a single data type.
{ -- | Name of the data type.

-- | Kinds of type parameters.

-- | Constructors of is data type, or Nothing if there are
--   too many to list (like with `Int`).
, dataDefCtors          :: Maybe [(n, [Type n])] }

-- | A table of data type definitions,
--   unpacked into type and data constructors so we can find them easily.
{ dataDefsTypes :: Map n (DataType n)
, dataDefsCtors :: Map n (DataCtor n) }

-- | The mode of a data type records how many data constructors there are.
--   This can be set to 'Large' for large primitive types like Int and Float.
--   In this case we don't ever expect them all to be enumerated
--   as case alternatives.
data DataMode n
= DataModeSmall [n]
| DataModeLarge

-- | Describes a data type constructor, used in the `DataDefs` table.
data DataType n
= DataType
{ -- | Name of data type constructor.
dataTypeName       :: n

-- | Kinds of type parameters to constructor.
, dataTypeParamKinds :: [Kind n]

-- | Names of data constructors of this data type,
--   or `Nothing` if it has infinitely many constructors.
, dataTypeMode       :: DataMode n }

-- | Describes a data constructor, used in the `DataDefs` table.
data DataCtor n
= DataCtor
{ -- | Name of data constructor.
dataCtorName       :: n

-- | Field types of constructor.
, dataCtorFieldTypes :: [Type n]

-- | Name of result type of constructor.
, dataCtorTypeName   :: n }

-- | An empty table of data type definitions.

-- | Insert a data type definition into some DataDefs.
= let  defType = DataType
{ dataTypeName       = nType
, dataTypeParamKinds = ks
, dataTypeMode       = defMode }

defMode = case mCtors of
Nothing    -> DataModeLarge
Just ctors -> DataModeSmall (map fst ctors)

makeDefCtor (nCtor, tsFields)
= DataCtor
{ dataCtorName       = nCtor
, dataCtorFieldTypes = tsFields
, dataCtorTypeName   = nType }

defCtors = case mCtors of
Nothing  -> Nothing
Just cs  -> Just \$ map makeDefCtor cs

\$ Map.fromList [(n, def) | def@(DataCtor n _ _)
<- concat \$ maybeToList defCtors] }