Haskell类型和typeclasses声明



我试图更好地理解Haskell中的类和实例。因此,我正在调查:

http://learnyouahaskell.com/making-our-own-types-and-typeclasses

在这里,他们建议尝试:

instance (Eq m) => Eq (Maybe m) where  
Just x == Just y = x == y  
Nothing == Nothing = True  
_ == _ = False  

但当我这样做时,我会得到以下输出:

tryouts.hs:58:10: error:
Duplicate instance declarations:
instance Eq m => Eq (Maybe m) -- Defined at tryouts.hs:58:10
instance Eq a => Eq (Maybe a) -- Defined in `GHC.Maybe'
  1. 我该如何克服这一点并实例化我自己的类型类声明?

  2. 作者认为,课堂前的(Eq m) => Eq对约束实例的内容很重要。这明显不同于在类级别(例如(定义Eq时这样做。然而,我不确定我是否理解其中的区别。这可能是我不理解OOP中类型类和正则类之间的区别以及前者的"继承"性质的地方。

  1. 如何克服这一点并实例化我自己的类型类声明

错误表明在模块中,它已经包含这样的实例。事实上,它在语义上完全相同,正如我们在源代码中看到的那样:

data  Maybe a  =  Nothing | Just a
deriving ( Eq  -- ^ @since 2.01
, Ord -- ^ @since 2.01
)

实现Eq的默认方法是,如果两个项的数据构造函数相同,并且参数在元素方面相等,则返回True

您可以定义自己的类型,然后定义实例,例如:

data Maybe2 a = Nothing2 | Just2 a
instance Eq m => Eq (Maybe2 m) where  
Just2 x == Just2 y = x == y  
Nothing 2== Nothing2 = True  
_ == _ = False

作者认为类前面的(Eq m) => Eq对于约束实例的内容很重要。这明显不同于在类级别(例如,当你定义Eq时(这样做。然而,我不确定我理解区别是什么。这可能是我不理解OOP中类型类和正则类之间的区别以及前者的"继承"性质的地方。

如果您要使用:

class Eq a => Eq (f a) where
...

那么这意味着Eq (Maybe a)将暗示Eq a,所以情况正好相反。然而,这永远不会起作用,因为如果Eq (Maybe Int)是实例,那么Eq Int是实例,但是Eq Int只能是Int ~ f a的实例(Intf a的类型相同(,并且aEq的实例。

  1. 你真的不能"重新定义";CCD_ 16代替CCD_。也就是说,可能有一种方法可以通过{-#LANGUAGE NoImplicitPrelude #-}重新定义它,并小心地导入足够多的类型和类型类,以避免导入包含Maybe aEq定义的文件,或者可能可以使用其中一个杂注来允许重叠声明,但我对此并不熟悉,所以不要相信我的话。

  2. Eq m => Eq (Maybe m)意味着为了使Maybe m成为Eq类型类的实例,m必须已经是Eq的实例。这是很自然的,因为为了比较Just aJust b,您需要能够比较ab。因此,您无法比较Just (+)Just (-)的相等性。

您可以尝试使用默认从Prelude导入的另一种方法-使用hiding。在这种情况下,它可以看起来像这样:

import Prelude hiding (Maybe, Just, Nothing)
data  Maybe a  =  Nothing | Just a
instance (Eq m) => Eq (Maybe m) where  
Just x == Just y = x == y  
Nothing == Nothing = True  
_ == _ = False  

最新更新