Search code examples
haskelltypesrestrictiontype-parametercustom-data-type

Haskell - Restrict data parameters


I am trying to create the following datatypes:

data ExprValues = ExprNum Int |
                  ExprIdent String |
                  ExprChar Char |
                  ExprString String
                  deriving(Eq, Show, Read)

data ExprOverall = ExprFunCall ExprValues  --correct this to use ExprIdent solely
                   deriving(Eq, Show, Read) 

However, as it is indicated in the comment, I want that ExprValues next to the ExprFuncall to accept ExprIdent String only, not the other ExprValues. How am I able to do it?


Solution

  • First off, if you want to allow only the constructor, why not just “inline” it – store a String right in ExprOverall and be done?

    But more generally, this sort of restriction can be implemented with GADTs. Often, especially for such AST-like types, you want to express the overall type the expression stands for. There, ExprIdent might be polymorphic while the others are concrete:

    {-# LANGUAGE GADTs #-}
    
    data ExprValues a where
      ExprNum :: Int -> ExprValues Int
      ExprIdent :: String -> ExprValues a
      ExprChar :: Char -> ExprValues Char
      ExprString :: String -> ExprValues String
    

    Then, for use in ExprOverall you select a unique tag-type that is only applicable to the ExprIdent constructor (because that allows any type variable a, whereas the others are specific to a concrete type).

    data FreeIdentifier
    
    data ExprOverall = ExprFunCall (ExprValues FreeIdentifier)