我正在尝试找出类型类的目的,如果不使用类型类,还有什么。
类型类是定义多态函数的一种方法吗?
类型类是定义多态函数的唯一方法吗?例如:
class Eq a where
(==), (/=) :: a -> a -> Bool
x /= y = not (x == y)
instance Eq Bool where
False == False = True
True == True = True
_ == _ = False
我可以在不使用类型类Eq
的情况下为Bool
(和任何其他类型)定义==
和/=
吗?
如果有任何其他方法,我什么时候应该使用哪种方法来定义多态函数,通过使用类型类还是使用其他方式?
你总是可以编写不受约束的多态函数,这不需要任何类型类。一个简单的例子是
length :: [a] -> Int
– 这在没有类型类的情况下工作,并且(好吧,因为)它适用于任何类型的a
。也就是说,length
实际上并不关心该列表中的值是什么,它只关心包含这些值的结构。它实际上从未对这些值本身执行任何操作,而多态类型实际上可以保证这一点。
如果你需要的多态任务是这种形式,即你实际上不需要访问的类型,你只知道它在那里,那么你不应该编写/调用类型类,只需使用 ML 风格的参数化多态性,如length
中所示。但是,很多时候,您需要访问值本身,以某种方式检查它们。但是,在不限制特定具体类型的情况下执行此操作是类型类的用途。Eq
,正如你自己引用的那样,就是一个例子。
类型类是定义多态函数的一种方式吗?
是的,这是一种方式。但不是唯一的方法。例如,参数多态性只是意味着如果你定义一个像init :: [a] -> [a]
这样的函数,它将适用于任何a
。类型类用于临时多态性:根据类型,实现可以完全不同。这与参数多态性相反,在参数多态性中,无论a
的类型如何,head
函数始终相同。
类型类是定义多态函数的唯一方法吗?
否,请参阅上一节。
我可以在不使用类型类
Eq
的情况下为Bool
(和任何其他类型)定义==
和/=
吗?
这取决于所有类型的实现是否相同。您可以使用-XNoImplicitPrelude
标志来避免导入Prelude
,然后您可以定义自己的(==)
函数。
OOP 和 haskell 中的多态函数是有区别的,我这么说是因为术语"多态性"通常在 OOP 中使用。
例如,列表上的函数是多态的:
cons:: a -> [a] -> [a]
cons x xs = x:xs
其中 a 是多态类型,那里没有类型类。
顺便说一下,默认情况下,有一种方法可以快速实现类型类,例如Eq
或Show
,例如:
data MBool = MTrue | MFalse deriving (Eq, Show)
所以,区别在于类型类是一个约束,想象一下这个带有列表的函数:
mapShow :: Show a => [a] -> [String]
mapShow = map show
那是不同的,因为现在,a是受限制的,它不能是任何"a"。它应该实现类型类Show
。
总之,您可以看到cons
函数中的a
类型比函数Show => a -> a
类型更通用或抽象mapShow
。