我认为GADT很棒,直到我尝试用GADTs"表达任何"表达式。分散在互联网上使用的例子。
传统的ADT以免费的方式提供定义平等。在GADT中代码:
data Expr a where
(:+:) :: (Show a, Eq a) => Expr a -> Expr a -> Expr a
(:-:) :: (Show a, Eq a) => Expr a -> Expr a -> Expr a
(:*:) :: (Show a, Eq a) => Expr a -> Expr a -> Expr a
(:/:) :: (Show a, Eq a) => Expr a -> Expr a -> Expr a
(:=:) :: (Show a, Eq a) => Expr a -> Expr a -> Expr Bool
(:<:) :: (Show a, Eq a) => Expr a -> Expr a -> Expr Bool
(:>:) :: (Show a, Eq a) => Expr a -> Expr a -> Expr Bool
(:>=:) :: (Show a, Eq a) => Expr a -> Expr a -> Expr Bool
(:<=:) :: (Show a, Eq a) => Expr a -> Expr a -> Expr Bool
(:<>:) :: (Show a, Eq a) => Expr a -> Expr a -> Expr Bool
EOr :: Expr Bool -> Expr Bool -> Expr Bool
EAnd :: Expr Bool -> Expr Bool -> Expr Bool
ENot :: Expr Bool -> Expr Bool
ESymbol :: (Show a, Eq a) => String -> Expr a
ELiteral :: (Show a, Eq a) => a -> Expr a
EFunction :: (Show a, Eq a) => String -> [Expr a] -> Expr a
deriving (Eq)
我得到(非常可以理解):
• Can't make a derived instance of ‘Eq (Expr a)’:
Constructor ‘:+:’ has existentials or constraints in its type
Constructor ‘:-:’ has existentials or constraints in its type
Constructor ‘:*:’ has existentials or constraints in its type
Constructor ‘:/:’ has existentials or constraints in its type
Constructor ‘:=:’ has existentials or constraints in its type
Constructor ‘:<:’ has existentials or constraints in its type
Constructor ‘:>:’ has existentials or constraints in its type
Constructor ‘:>=:’ has existentials or constraints in its type
Constructor ‘:<=:’ has existentials or constraints in its type
Constructor ‘:<>:’ has existentials or constraints in its type
Constructor ‘EOr’ has existentials or constraints in its type
Constructor ‘EAnd’ has existentials or constraints in its type
Constructor ‘ENot’ has existentials or constraints in its type
Constructor ‘ESymbol’ has existentials or constraints in its type
Constructor ‘ELiteral’ has existentials or constraints in its type
Constructor ‘EFunction’ has existentials or constraints in its type
Possible fix: use a standalone deriving declaration instead
• In the data declaration for ‘Expr’
如果我没有为每个构造函数设置Eq
限制,那么这是可以理解的,但现在我必须为所有这些构造函数编写琐碎的相等规则。
我觉得有更好的方法可以解决这个问题。
答案 0 :(得分:8)
传统deriving
无法处理GADT约束。原则上,独立派生可以:
{-# LANGUAGE GADTs, StandaloneDeriving #-}
data Expr a where
(:+:) :: (Show a, Eq a) => Expr a -> Expr a -> Expr a
...
deriving instance Eq (Expr a)
但是,这对您没有帮助,因为Eq
实例是不可能的。你将如何比较
(1 :<: (2 :: Expr Int)) == (pi :<: (sqrt 2 :: Expr Double))
这是不可能的; GADT约束
(:<:) :: (Show a, Eq a) => Expr a -> Expr a -> Expr Bool
只强制Expr
中的两个值具有相同的类型且Eq
,但它并没有告诉您有关<的类型< em>不同的表达式。