I've been writing an AST to build a DSL in Haskell and, for that, I'm using GADTs to define expressions such as:
data Expr a where
I :: Int -> Expr Int
B :: Bool -> Expr Bool
Add :: Expr Int -> Expr Int -> Expr Int
Mul :: Expr Int -> Expr Int -> Expr Int
Eq :: Expr Int -> Expr Int -> Expr Bool
However, I would like for expressions like Add and Mul to also work with other numeric values, from types Float and Double. How would I be able to achieve such results?
You could generalize Expr
a bit and use
data Expr a where
Lit :: a -> Expr a -- why not just let anything in?
Add :: Num a => Expr a -> Expr a -> Expr a -- only `a` w/ `Num a` can be added
Mul :: Num a => Expr a -> Expr a -> Expr a -- only `a` w/ `Num a` can be multiplied
Eq :: Eq a => Expr a -> Expr a -> Expr Bool -- only `a` w/ `Eq a` can be added
Then again, the question really is: what are you trying to do with it? If you just want to explicitly construct an AST that type-checks and then be able to evaluate it, the above works just fine.
eval :: Expr a -> a
eval (Lit x) = x
eval (Add x y) = eval x + eval y
eval (Mul x y) = eval x * eval y
eval (Eq x y) = eval x == eval y