以下内容无法编译:
data Point a b = Point { x :: a
, y :: b
} deriving (Show)
instance Eq (Point a b) where
(Point x _) == (Point y _) = x == y
错误是:
No instance for (Eq a)
arising from a use of `=='
In the expression: x == y
In an equation for `==': (Point x _) == (Point y _) = x == y
In the instance declaration for `Eq (Point a b)'
但是,如果我将类型类添加到实例中,那么它可以工作:
data Point a b = Point { x :: a
, y :: b
} deriving (Show)
instance (Eq a) => Eq (Point a b) where
(Point x _) == (Point y _) = x == y
编译器是否可以看到我在那里使用a == a
并推断出a
必须位于类型Eq
中?
答案 0 :(得分:15)
可以表示a
必须在类型类Eq
中。这正是它抱怨的原因。您声明了instance Eq (Point a b)
,其中表示Point a b
形式的类型位于{em>任何类型Eq
和{{1}的a
类型类中},但您提供了b
的定义,仅当==
是a
的成员时才有效。
这两件事是不一致的,所以Haskell不会试图猜测哪一个是你真正的意思,它只是将其报告为错误。该语言没有 以这种方式工作,但这是一个深思熟虑的设计选择。
答案 1 :(得分:5)
想象一个功能
equals :: a -> a -> Bool
equals = (==)
编译器显然可以推断出equals的类型应该是Eq a => a -> a -> Bool
。但它错了,因为你声明你的类型适用于所有的。
Typeclass实例是类似的,除了我们没有选择让它们以我们可以省略equals
的类型声明的方式推断它们。因此,有必要以与指定函数的类型签名相同的方式来规定约束,您还必须指定约束。
也就是说,ghc不会推断仅约束;它要么必须推断整个签名,要么不推断它。 (嗯,它推断出任何一种方式,但推断必须比你输入的更为通用,如果你输入它 - 并且约束符合这个要求)。
将您的初始instance Eq (Point a b)
视为(==) :: (Point a b) -> (Point a b) -> Bool
,这是不可能以您喜欢的方式定义的,因为它赋予该主体(==) :: Eq a => (Point a b) -> (Point a b) -> Bool
。