{-# LANGUAGE GADTs #-}

data Expr a where
    Number  :: Int -> Expr Int
    Boolean :: Bool -> Expr Bool
    Not     :: Expr Bool -> Expr Bool
    Even    :: Expr Int -> Expr Bool
    Add     :: Enum a => Expr a -> Expr a -> Expr Int
    Max     :: Ord a => Expr a -> Expr a -> Expr a

evaluate :: Expr a -> a
evaluate (Number n)  = n
evaluate (Boolean p) = p
evaluate (Add n m)   = fromEnum (evaluate n) + fromEnum (evaluate m)
evaluate (Even n)    = even $ evaluate n
evaluate (Not p)     = not $ evaluate p
evaluate (Max x y)   = max (evaluate x) (evaluate y)