haskell类型

Haskell 类型

在Int等默认内置类型外,haskell支持创建自定义的类型系统.这里说的类型更像c中的struct和class,可以有多个类型和不同取值的组合.对于稍微复杂的系统,使用自定义和库里的类型是不可避免的

数据类型定义

基础数据类型

1
data Bool = False | True

data 关键字用于定义新的数据类型,Bool 是类型名,FalseTrue 是值构造器,分别表示布尔值的两种可能性.| 表示或.
注意:类型名和值构造器的首字母必须大写.

  • 数据类型:Haskell 中的数据类型定义类似于枚举,表示一个类型的所有可能值.
  • 值构造器:它们是构造类型值的方式,可以理解为是某种“标签”,标明当前值属于哪个分支.

eg:

1
data Shape = Circle Float Float Float | Rectangle Float Float Float Float
  • CircleRectangle 是值构造器,同时也是函数,接受 Float 类型参数.
  • 类型 Shape 表示几何图形.

  • Circle Float Float Float:第一个和第二个 Float 表示圆心的坐标,第三个 Float 表示半径.

  • Rectangle Float Float Float Float:四个 Float 分别表示矩形对角线两点的坐标.

我们可以基于 Shape 定义函数,例如计算面积:

1
2
3
surface :: Shape -> Float
surface (Circle _ _ r) = pi * r ^ 2
surface (Rectangle x1 y1 x2 y2) = (abs $ x2 - x1) * (abs $ y2 - y1)

自动派生类型

可以使用 deriving 自动生成某些类型类的实例:

1
data Shape = Circle Float Float Float deriving (Show)
  • deriving:Haskell 提供了自动派生功能,能够为常见的类型类生成默认实现.这允许 Shape 类型的值可以直接使用print的方法输出,就行Int和Char一样.可以理解为oop中的子类

嵌套数据类型

1
2
data Point = Point Float Float deriving (Show)
data Shape = Circle Point Float | Rectangle Point Point deriving (Show)

通过组合类型 Point,Shape 描述了更复杂的几何形状.

  • 组合数据类型:Point 是一个更抽象的数据类型,用于表示二维空间中的点.Shape 使用 Point 类型参数化了几何形状,提升了表达能力.


类型参数与泛型

1
data Maybe a = Nothing | Just a

Maybe 是带类型参数 a 的类型构造器,可表示“可能存在”或“不存在”的值,例如 Maybe IntMaybe String.

  • 类型参数:a 是一个占位符,表示可以接受任何类型.
  • 用途:Maybe 类型常用于处理可能失败的计算,类似于其他语言中的 OptionalNullable.

泛型向量定义

1
2
3
4
data Vector a = Vector a a a deriving (Show)

vplus :: (Num t) => Vector t -> Vector t -> Vector t
(Vector i j k) `vplus` (Vector l m n) = Vector (i+l) (j+m) (k+n)

此定义适用于不同类型的三维向量.

  • 泛型参数 a:表示向量的分量类型,例如可以是 IntFloat.
  • vplus 函数:定义了两个向量的逐元素加法.


类型类与实例

类型类类似于接口,定义了一组通用行为.例如,Eq 类型类定义了相等性:

1
2
3
4
5
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
x /= y = not (x == y)
x == y = not (x /= y)
  • 类型类:类似于接口,描述了一组类型支持的操作.
  • 默认实现:Eq 中提供了 ==/= 的默认实现,减少了实例化类型类的重复工作.

为数据类型实现类型类

以交通信号灯为例:

1
2
3
4
5
6
7
data TrafficLight = Red | Yellow | Green

instance Eq TrafficLight where
Red == Red = True
Yellow == Yellow = True
Green == Green = True
_ == _ = False
  • instance:用于为具体的数据类型定义类型类的实现.
  • 模式匹配:通过具体值的匹配,实现 TrafficLightEq 实例.

常见类型类

  • Eq: 支持相等性判断.
  • Ord: 支持排序.
  • Show: 支持打印.
  • Read: 支持字符串解析.
  • Enum: 支持枚举.
  • Bounded: 支持上下界.

eg:

1
2
3
4
5
data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday
deriving (Eq, Ord, Show, Read, Bounded, Enum)

ghci> [Thursday .. Sunday]
[Thursday,Friday,Saturday,Sunday]
  • 多重派生:Day 同时派生了多个类型类实例,使其支持相等性比较、排序、打印等操作.
  • 范围操作:BoundedEnum 的实例使得可以生成枚举范围.


Functor 与递归数据结构

Functor 类型类

Functor 提供了一种将函数应用于容器内值的方式:

1
2
class Functor f where
fmap :: (a -> b) -> f a -> f b
  • f 是类型构造器:它接受一个类型参数,例如 Maybe 或列表.
  • fmap:表示将函数应用到容器(如 Maybe 或树)中的每个元素.

Maybe 为例:

1
2
3
instance Functor Maybe where
fmap f (Just x) = Just (f x)
fmap f Nothing = Nothing
  • Maybe 的 Functor 实例:定义了如何将函数映射到 Maybe 类型的值上.
  • 用途:允许对容器中的值进行函数操作,而不需要显式解包.

递归数据结构:树

1
2
3
4
data Tree a = EmptyTree | Node a (Tree a) (Tree a) deriving (Show)

singleton :: a -> Tree a
singleton x = Node x EmptyTree EmptyTree

通过递归方式定义操作:

1
2
3
4
5
6
treeInsert :: (Ord a) => a -> Tree a -> Tree a
treeInsert x EmptyTree = singleton x
treeInsert x (Node a left right)
| x == a = Node x left right
| x < a = Node a (treeInsert x left) right
| x > a = Node a left (treeInsert x right)
  • 递归定义:通过递归调用 treeInsert,构造或更新树结构.
  • 平衡性:尽管此处未实现平衡逻辑,但该方法可用于构建基本的二叉搜索树.更复杂的平衡树在haskell中的实现机制需要多加考虑,因为haskell中对于已有数据的修改本质都是创建新副本,使得整个修改过程构成一个巨大的可持久化结构,关于空间使用还需注意