类型与类型类

2025-09-11 00:00    #  

Haskell:类型与类型类 读书笔记核心内容

一、 核心概念:静态类型与类型推断

  1. 静态类型系统 (Static Type System)

    • Haskell 是静态类型的。这意味着每个表达式的类型在编译时就已经确定了。
    • 这样做的好处是极大地提高了代码的安全性。例如,你不能将一个布尔值和数字相除,这样的错误在编译阶段就会被发现,而不是在程序运行时崩溃。
  2. 类型推断 (Type Inference)

    • 与 Java 或 Pascal 不同,Haskell 具有强大的类型推断能力。
    • 不必为每个函数或表达式显式地写出类型。Haskell 编译器通常能自动推断出它们的类型。
    • 尽管如此,为顶层函数(toplevel functions)编写明确的类型签名(Type Declaration)被认为是最佳实践。

二、 类型 (Types)

  1. 什么是类型?

    • 类型是给表达式贴上的“标签”,用于说明该表达式属于哪个“类别”。例如:
      • TrueBool 类型。
      • "hello"[Char] 类型(即 String)。
      • 'a'Char 类型。
      • (True, 'a')(Bool, Char) 类型。
  2. 在 GHCI 中检查类型

    • 使用 :t 命令可以查看任何表达式的类型。
    • 例如::t 'a' 会返回 'a' :: Char
    • :: 读作“具有类型”。
  3. 常见的内置类型

    • Int:有界的整数(通常为 32 或 64 位)。它更高效。
    • Integer:无界的整数。可以用来表示任意大的数字,但效率低于 Int
    • Float:单精度浮点数。
    • Double:双精度浮点数。
    • Bool:布尔值,只有 TrueFalse 两个值。
    • Char:单个字符。
    • String:字符串,它实际上是 [Char](字符列表)的类型别名。

三、 函数的类型

  1. 类型签名 (Type Signatures)
    • 函数也有类型。我们使用 :: 来声明它。
    • 格式:functionName :: argumentType1 -> argumentType2 -> returnType
    • 例如:addThree :: Int -> Int -> Int -> Int
    • 这表示 addThree 函数接收三个 Int 类型的参数,并返回一个 Int 类型的值。最后一个类型总是返回类型

四、 类型变量 (Type Variables) 与多态

  1. 多态函数 (Polymorphic Functions)
    • 当一个函数的类型签名中包含小写字母开头的名称(如 a, b, t)时,这些就是“类型变量”。
    • 类型变量意味着“可以是任何类型”。
    • 例如,head 函数的类型是 head :: [a] -> a
    • 这表示 head 接受一个任何类型 a 的元素组成的列表[a]),并返回一个该类型 a 的元素。它不关心列表里具体是 Int 还是 String
    • 这类似于其他语言中的“泛型”。

五、 类型类 (Typeclasses)

  1. 什么是类型类?

    • 类型类不是面向对象语言中的“类”。它更像是定义行为的接口(Interface)
    • 如果一个类型是某个类型类的“实例”(instance),那么它必须实现了该类型类所描述的行为(即特定的函数)。
  2. 类约束 (Class Constraints)

    • 在类型签名中,使用 => 来表示类型约束。
    • 例如:(==) :: (Eq a) => a -> a -> Bool
    • 这读作:== 函数接受两个类型为 a 的值,并返回一个 Bool前提条件是:类型 a 必须是 Eq 类型类的实例
  3. 常见的类型类

    • Eq:用于支持相等性比较的类型。它提供了 ==/= (不等于) 函数。
    • Ord:用于支持排序的类型。它提供了 <, >, <=, >= 等函数。一个类型必须首先是 Eq 的实例,才能成为 Ord 的实例。
    • Show:用于可以转换成字符串的类型。它提供了 show 函数(例如 show 3 返回 "3")。
    • ReadShow 的反向操作。用于将字符串转换回特定类型。它提供了 read 函数。
      • 注意:使用 read 时,Haskell 常常无法推断你想要的目标类型,因此需要显式类型注解,例如:read "5" :: Int
    • Enum:用于可以枚举的类型(即有顺序的)。这使得它们可以用于列表的范围表达式,如 ['a'..'e'][1..5]
    • Bounded:用于有明确上界和下界的类型。它提供了 minBoundmaxBound
    • Num:用于“数字”的类型类。像 20 这样的字面量本身是多态的,其类型是 (Num t) => t。这意味着 20 既可以是 Int,也可以是 FloatDouble,Haskell 会根据上下文来推断。
    • IntegralNum 的子类,只包括整数(Int, Integer)。
    • FloatingNum 的子类,只包括浮点数(Float, Double)。
  4. fromIntegral 函数

    • 这是一个非常有用的函数,其类型为 fromIntegral :: (Num b, Integral a) => a -> b
    • 它用于将一个整数类型(如 Int)转换成一个更通用的数字类型(如 FloatDouble),以便在计算中混合使用它们。