繁体   English   中英

在Haskell中,为什么我需要在实例声明中指定类型类?

[英]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形式的类型在任何类型abEq类型类中,但是您给出了==的定义,仅当aEq的成员时才有效。

这两件事情是不一致的,所以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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM