![](/img/trans.png)
[英]Why do I have to specify typeclass in function if it was declared in data definition?
[英]In Haskell, why do I need to specify the typeclass in an instance declaration?
以下内容无法编译:
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
?
它可以平分是a
必须在类型类Eq
。 这正是它抱怨的原因。 您声明了instance Eq (Point ab)
,它表示Point ab
形式的类型在任何类型a
和b
的Eq
类型类中,但是您给出了==
的定义,仅当a
是Eq
的成员时才有效。
这两件事情是不一致的,所以Haskell并不试图猜测哪一个是你的意思,它只是将其报告为错误。 语言没得工作方式,但它是一个经过深思熟虑的设计选择。
想象一个功能
equals :: a -> a -> Bool
equals = (==)
编译器显然可以推断出equals的类型应该是Eq a => a -> a -> Bool
。 但它错误,因为你声明你的类型适用于所有a。
类型类实例是类似的,除了我们没有选择让它们以我们可以省略equals
的类型声明的相同方式被推断。 因此,有必要以与指定函数的类型签名相同的方式来规定约束,您还必须指定约束。
也就是说,ghc不会只推断约束; 它要么必须推断整个签名,要么不推断它。 (嗯,它推断出任何一种方式,但推理必须比你输入它更通用,如果你输入它 - 并且约束符合这个要求)。
把你的初始instance Eq (Point ab)
想象为(==) :: (Point ab) -> (Point ab) -> Bool
,这是不可能以你喜欢的方式很好地定义,因为给它那个体会有(==) :: Eq a => (Point ab) -> (Point ab) -> Bool
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.