以下内容无法编译:
data Point a b = Point { x :: a
, y :: b
} deriving (Show)
instance Eq (Point a b) where
(Point x _) == (Point y _) = x == y
Run Code Online (Sandbox Code Playgroud)
错误是:
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)'
Run Code Online (Sandbox Code Playgroud)
但是,如果我将类型类添加到实例中,那么它可以工作:
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
Run Code Online (Sandbox Code Playgroud)
编译器不能看到我a == a在那里使用并推断出a必须在类型类中Eq吗?
Ben*_*Ben 15
它可以降级a必须在类型类中Eq.这正是它抱怨的原因.您声明instance Eq (Point a b),它说,种形式Point a b是在Eq类型类的任何类型的a和b,但你给的定义==时,只有作品a是其成员Eq.
这两件事情是不一致的,所以Haskell并不试图猜测哪一个是你的意思,它只是将其报告为错误.语言不具有以工作的方式,但它是一个经过深思熟虑的设计选择.
想象一个功能
equals :: a -> a -> Bool
equals = (==)
Run Code Online (Sandbox Code Playgroud)
编译器显然可以推断出equals的类型应该是Eq a => a -> a -> Bool.但它错误,因为你声明你的类型适用于所有a.
Typeclass实例是类似的,除了我们没有选择让它们以我们可以省略类型声明的相同方式被推断equals.因此,有必要以与指定函数的类型签名相同的方式来规定约束,您还必须指定约束.
也就是说,ghc不会只推断约束; 它要么必须推断整个签名,要么不推断它.(嗯,它推断出任何一种方式,但推理必须比你输入它更通用,如果你输入它 - 并且约束符合这个要求).
把你的初始想象instance Eq (Point a b)为(==) :: (Point a b) -> (Point a b) -> Bool,这是不可能以你喜欢的方式很好地定义,因为给它的身体会有(==) :: Eq a => (Point a b) -> (Point a b) -> Bool.