如何在 Haskell 中的 DSL 中定义类型?

How to define types in a DSL in Haskell?

我一直在编写 AST 以在 Haskell 中构建 DSL,为此,我使用 GADT 来定义表达式,例如:

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

但是,我希望像 Add 和 Mul 这样的表达式也可以处理 Float 和 Double 类型的其他数值。 我怎样才能达到这样的结果?

您可以概括一下 Expr 并使用

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

话又说回来,真正的问题是:你想用它做什么?如果你只是想显式地构造一个 type-checks 的 AST 然后能够对其进行评估,上面的方法就可以了。

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