制造我们自己的类型和类型类

2025-09-11 00:00    #haskell  

chapter_8 制造我们自己的类型和类型类

本章是 Haskell 学习过程中的一个重要转折点。它标志着从“使用”语言特性转向“创造”语言特性。核心内容围绕两个方面:一是如何使用 datatype 关键字定义自己的数据结构,二是如何使用 class 关键字定义自己的接口(即类型类),并用 instance 来实现它。

1. 自定义数据类型 (Data Types)

Haskell 提供了两种主要方式来创建新类型:datatype

a. data 关键字:创建全新的数据结构

data 关键字用于定义一个全新的数据类型。这是本章的重点。

b. type 关键字:创建类型别名

type 关键字不会创建新类型,它只是为现有类型提供一个“别名”或“同义词”。

2. 派生 (Deriving)

Haskell 可以为我们自动实现某些标准类型类的实例,如 Show, Eq, Ord, Read

1data Point = Point Float Float deriving (Show, Eq)

3. 类型类 (Typeclasses)

类型类是 Haskell 实现“接口”或“多态”的方式。它定义了一组函数签名,任何类型只要实现了这些函数,就可以成为该类型类的“实例”。

a. 核心概念对比

b. class 关键字:定义类型类

class 关键字用于定义一个新的类型类(接口)。

1class Eq a where
2    (==) :: a -> a -> Bool
3    (/=) :: a -> a -> Bool
4    x == y = not (x /= y)  -- 默认实现
5    x /= y = not (x == y)  -- 默认实现

c. instance 关键字:实现类型类

instance 关键字用于为特定类型提供类型类的具体实现。

1-- 为我们之前定义的 Shape 类型实现 Eq
2instance Eq Shape where
3    (Circle _ _ r1) == (Circle _ _ r2) = r1 == r2
4    (Rectangle _ _ w1 h1) == (Rectangle _ _ w2 h2) = (w1 == w2) && (h1 == h2)
5    _ == _ = False -- 任何不同类型(如 Circle 和 Rectangle)的比较都为 False

4. 类型类作为约束 (Constraints)

类型类最强大的用途是约束函数签名,使其具有通用性(多态)。

1find :: (Eq a) => a -> [a] -> Maybe Int

总结与反思

  1. data 是核心data 关键字是 Haskell 中数据建模的基础。通过它,我们可以创建出具有高度表现力的数据结构,例如 Maybe aEither a b,它们在函数式编程中用于处理错误和可选值。
  2. 类型类即接口:类型类(Typeclasses)是 Haskell 对“接口”的解答。它比 Java 的 interface 或 C++ 的抽象基类更灵活,因为它允许我们在类型定义之后“追溯性”地添加实现(如我们为 Shape 添加 Eq 实例),实现了数据和行为的分离。
  3. 约束即多态(Eq a) => 这样的约束是 Haskell 实现泛型编程或多态的方式。它允许函数在不知道具体类型的情况下,安全地操作数据,只要这些数据满足特定接口(类型类)的要求。