Haskell类型类
Haskell的类型类
类型类(typeclass
)是定义行为的接口。类似于其他语言中的interface
,比如C++的抽象接口类。如果一个类型是某类型类的实例(instance),那么他必须实现该类型定义的行为。千万不要将Haskell的类型类与面向对象语言中的类Class搞混淆
假设定义类一个类型类(接口)名字叫做吃饭,然后又定义了鸟、人、鱼作为吃饭类型类的实例,那么鸟、人、鱼类就需要实现怎么吃饭这个行为。如果用C++的语言表达,可能是需要创建一个类,在里面声明了一个抽象函数(virtual void eat() = 0
), 其他的类继承了这个类,那么必须要实现它。
不过个人觉得,这个思想的方法,Rust中的trait似乎更贴切一点。
使用:t (==)
查看 == 在Haskell中的函数原型
1 |
|
这里出现了一个新的符号 => (实际在上篇文章中使用到了),它的左侧叫做类型约束,这里的 == 和 + 分别约束了使用 Eq和Num两个类。
Eq 类型类
用于判断相等性的类型,Eq类定义了等式(==)和不等式(/=)。由Prelude导出的所有基本数据类型都是Eq的实例,并且Eq可以为其成分也是Eq实例的任何数据类型派生。 Haskell官方没有定义Eq一定要实现什么。 然而,==通常期望实现等价关系,其中两个比较相等的值通过“公共”函数无法区分,“公共”函数是不允许查看实现细节的函数。 例如,对于表示非规范化自然数模100的类型,“公共”函数不会在1和201之间产生差异。
最小完整定义
1 |
|
Ord 类型类
Ord 类用于可比较大小的类型。 Ord的实例可以为任何组成类型为Ord的用户定义数据类型派生。数据声明中构造函数的声明顺序决定派生Ord实例的顺序。Ordering数据类型允许一次比较来确定两个对象的精确排序。
和Eq类似,取两个参数,返回一个Bool类型的值,用来表示是否满足对应的比较关系
最小完整定义
1 |
|
Show 类型类
将值转换为可读字符串。
Show的派生实例具有以下属性,它们与Read的派生实例兼容:
- show的结果是一个语法正确的Haskell表达式,只包含常量,只要在声明类型时有效地声明了固定性。它只包含在数据类型、括号和空格中定义的构造函数名称。当使用带标签的构造函数字段时,还会使用大括号、逗号、字段名和等号。
- 如果构造函数被定义为中缀操作符,那么showsPrec将生成构造函数的中缀应用。
- 如果x中的顶级构造函数的优先级小于d(忽略结合性),则表示将被括在括号中。因此,如果d为0,则结果永远不会被括号包围;如果d是11,则它总是用圆括号括起来,除非它是原子表达式。
- 如果构造函数是使用记录语法定义的,那么show将生成记录语法表单,其中字段的顺序与原始声明的顺序相同。
除函数以外的所有类型都是SHow的实例,可以使用show函数将值转换为字符串
1 |
|
最小完整定义
1 |
|
Read 类型类
解析字符串,生成值。
Read的派生实例做出以下假设,这些假设派生了Show obey的实例:
- 如果构造函数被定义为中缀操作符,那么派生的Read实例将只解析构造函数的中缀应用程序(而不是前缀形式)。
- 结合性不用于减少括号的出现,尽管可以使用优先级。
- 如果构造函数是使用记录语法定义的,则派生的Read将只解析记录语法形式,而且,字段必须按照与原始声明相同的顺序给出。
- 派生的Read实例允许在输入字符串的令牌之间使用任意的Haskell空白。还允许使用额外的括号。
Read可以看做Show相反的类型类,之前提到的所有类都是Read类型,read函数可以去一个字符串作为参数并转为Read的某个实例的类型
1 |
|
如果尝试使用read "4"
来得到生成一个数字4的效果,那么这是不可能的,会得到一个大大的报错。因为GHCI并不能准确知道到底要个什么玩意来满足屏幕面前的你
所以如果在没有一个表达式的情况下,或者说最好给read转换增加一个显示的类型注解
1 |
|
最小完整定义
1 |
|
Enum 类型类
Enum的实例对象都是可连续的(枚举),每一个值都有相应的后继和前驱,分别可以通过succ
和pred
得到。
1 |
|
Bounded 类型类
类型存在一个上限和下限,分别可以通过maxBound和minBound两个函数获得
1 |
|
Num 类型类
表示一个数值的类型类,它的实例都具有数的特征。
只有具有Show和Eq的实例类型,才可以成为Num类型类的实例
Floating 类型类
包含Float和Double两种浮点类型,用于存储浮点数。
使用Floating类型类的实例类型作为参数或者返回类型的函数,一般需要用到浮点数进行某种计算
Integral 类型类
另一种表示数值的类型类。Num类型类包含了实数和整数相关的所有类型,Integral只包含了整数。
详细的对于类型类的介绍可以参考以下官方文档链接:
https://hackage.haskell.org/package/ghc-prim-0.7.0/docs/GHC-Classes.html
https://hackage.haskell.org/package/base-4.15.1.0/docs/GHC-Show.html#t:Show
https://hackage.haskell.org/package/base-4.15.1.0/docs/Text-Read.html#v:Read