阿男的小窝

View the Project on GitHub

Haskell中Class的概念

Haskell中的Class设计与面向对象的语言有本质区别,并不是同一个概念。

比如,在Java当中,class用于定义一个物件(Object),而Haskell中的class用于表示一组功能(Functional)。

从这点来讲,Haskell的class更类似于Java中的interface,但是Java当中的interface是围绕着一个Object来设计的一组功能,而Haskell中的class是按照功能来划分出来的一组函数。

比如,在Java当中,我们可以写一个Color的class,用于描述颜色,以及对颜色的操作等等。这种思考方式叫做Object-Oriented(面向对象)。

在Haskell当中,我们不这样思考问题。我们会把一组有相关性的功能抽象出来,形成class。

比如Haskell自带的这两个class:

我们可以使用ghci中的:info命令来查看一下EqOrd两个class,并看一看它们的设计思想:

Prelude> :info Eq
class Eq a where
  (==) :: a -> a -> Bool
  (/=) :: a -> a -> Bool
...

上面是Eq class的输出片段,我们看到Eq里面定义了两个函数,分别是==/=。这两个函数的功能就是用于判断”等于”和”不等于”。

上面的函数当中并且没有定义具体的类型,两个函数的参数返回值定义都是:a -> a -> Bool

也就是接受两个相同类型的数据,然后返回Bool,也就是True/False类型的数据。

Eq类型因此定义了一种”行为”:判断相等性。

此外,Eq类型没有定义具体如何实现==/=,它只是定义了这两个函数要接受两个参数,给出比较结果,具体的实现交给具体的数据类型(data type)。

可以看到,Haskell的class是一种很抽象的函数类型定义。能达到这样的抽象程度,是被Haskell的整套类型系统支撑起来的。

在Java里面,实现interface的叫做class。

在Haskell里面,实现了class的叫做class instance。

我们可以看看具体实现了Eq class的instances。可以使用:info Eq来查看Eq class中包含哪些实现了它的instances:

Prelude> :info Eq
class Eq a where
  (==) :: a -> a -> Bool
  (/=) :: a -> a -> Bool
  {-# MINIMAL (==) | (/=) #-}
  	-- Defined in ‘GHC.Classes’
instance (Eq a, Eq b) => Eq (Either a b)
  -- Defined in ‘Data.Either’
instance Eq a => Eq [a] -- Defined in ‘GHC.Classes’
instance Eq Word -- Defined in ‘GHC.Classes’
instance Eq Ordering -- Defined in ‘GHC.Classes’
instance Eq Int -- Defined in ‘GHC.Classes’
instance Eq Float -- Defined in ‘GHC.Classes’
instance Eq Double -- Defined in ‘GHC.Classes’
instance Eq Char -- Defined in ‘GHC.Classes’
instance Eq Bool -- Defined in ‘GHC.Classes’

如上所示,我们可以看到有很多instances实现(derive)了Eq class,比如IntFloatDouble等等,它们都是Eq class的instances。

我们使用:info命令来看看Int

Prelude> :info Int
data Int = GHC.Types.I# GHC.Prim.Int# 	-- Defined in ‘GHC.Types’
instance Bounded Int -- Defined in ‘GHC.Enum’
instance Enum Int -- Defined in ‘GHC.Enum’
instance Eq Int -- Defined in ‘GHC.Classes’
instance Integral Int -- Defined in ‘GHC.Real’
instance Num Int -- Defined in ‘GHC.Num’
instance Ord Int -- Defined in ‘GHC.Classes’
instance Read Int -- Defined in ‘GHC.Read’
instance Real Int -- Defined in ‘GHC.Real’
instance Show Int -- Defined in ‘GHC.Show’

从上面的命令中,我们可以看到Int类型是一个具体的数据类型(data Int),而不像Eq的定义那样是个class(class Eq a where ...)。

此外,我们看到,Int除了实现了Eq class,还实现了很多其它的classes,比如EnumOrdShow等等。

在Haskell当中,我们称Int是derive了ShowOrdEq这些classes,也可以说IntOrdShowEq这些classes的instance。

Int自身叫做data type。

从上面的分析可以看到,Haskell的class和面向对象语言中的class有本质不同:Haskell的class定义功能行为,而不抽象出一个物件(object)。这就是functional language和object oriented language的一个本质区别。