我一直在使用类型安全评估器示例介绍一些介绍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。这甚至是正确的轨道吗?
感谢。
答案 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