Haskell GADT类型安全评估器:多个类型的常量项。

时间:2016-05-21 04:50:20

标签: haskell

我一直在使用类型安全评估器示例介绍一些介绍GADT的Haskell教程。很多评估者都在布尔和Int类型上运行。因此,具有函数(常量整数,常量布尔值,加法,乘法和校验等式)的赋值器的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

我对这个例子很满意,但我希望能够将常规常量类型定义为Int或Bool类型,而不是为Int和Bool分别设置条目。这可能吗。

如果我只在我的GADT中使用Type变量而不是Int或Bool,这似乎有效。

这就是上面的例子:

data Expr a where
  Con :: t -> Expr t
  Add :: Expr Int -> Expr Int -> Expr Int
  Mul :: Expr Int -> Expr Int -> Expr Int
  Eq  :: Expr Int -> Expr Int -> Expr Bool

那时Constant类型不够受限制,因为我可以有一个常量列表输入,或一个常量String / Float,其中我只想要常量为Int或Bool。

我已经考虑过使用TypeClasses(我认为)来解决这个问题,因为这似乎能够限制类型变量的“域”,例如使用“Ord”类会限制类型变量的可能类型。可以采取行

Con :: Ord t => t -> Term t

不幸的是,我不确定如何编写自己的类来将type变量限制为Boolean或Integer。这甚至是正确的轨道吗?

感谢。

1 个答案:

答案 0 :(得分:5)

使用像你要求的约束的想法可以像这样实现:

class Constant a

instance Constant Int
instance Constant Bool

data Expr a where
  C :: Constant a => a -> Expr a
  Add :: Expr Int -> Expr Int -> Expr Int
  Mul :: Expr Int -> Expr Int -> Expr Int
  Eq  :: Expr Int -> Expr Int -> Expr Bool

这会很好用我猜

eval :: Expr a -> a
eval (C a) = a
eval (Add a b) = eval a + eval b
eval (Mul a b) = eval a * eval b
eval (Eq a b) = eval a == eval b

另一方面,如果你想在常数本身上匹配,你可以使用另一个GADT:

module SO where

data Const a where
  ConstB :: Bool -> Const Bool
  ConstI :: Int -> Const Int

data Expr a where
  C :: Const a -> Expr a
  Add :: Expr Int -> Expr Int -> Expr Int
  Mul :: Expr Int -> Expr Int -> Expr Int
  Eq  :: Expr Int -> Expr Int -> Expr Bool

使用

λ> C (ConstB False)
C (ConstB False) :: Expr Bool
λ> C (ConstI 5)
C (ConstI 5) :: Expr Int