函数的类型从何而来?

考虑以下代码:

1
2
swap :: (a,b) -> (b,a)
swap (x, y) = (y, x)

这里并没有对 xy 的类型作任何要求,换言之,显然地,swap(1, 2) = (2, 1)。但是更进一步,swap('a', False) = (False, 'a'),并没有任何问题,所以只需要写 ab 即可。

但是这一段:

1
2
3
4
5
palindrome :: Eq a => [a] -> Bool
palindrome xs = reverse xs == xs

double :: Num a => a -> a
double x = x * 2

首先,palindrome 的运行依赖于 == 的实现。换言之,如果 [a] 中的 a 不支持 == 操作(也即不在 Eq 定义下),那么以下的语句是无法正常运行的,所以我们需要额外地限定 Eq a

进一步,double 的运行则依赖 *,所以我们要保证乘法这一行为合法。考虑限制 Num a,即说明 * 是良定的。

两个典型的类型类

(这些是 AI 生成的)

Integral 类型类(整数运算)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- div:整数除法(截断)
> 7 `div` 2 :: Int
3

-- mod:取模运算
> 7 `mod` 2 :: Int
1

-- quot 和 rem:截断向零除法
> (-7) `quot` 2 :: Int
-3
> (-7) `rem` 2 :: Int
-1

-- toInteger:转换为任意精度整数
> toInteger (maxBound :: Int)
9223372036854775807

Fractional 类型类(小数运算)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 普通除法:/
> 7.0 / 2.0 :: Double
3.5

-- 倒数:recip
> recip 4.0 :: Float
0.25

-- fromRational:有理数转换
> fromRational (3%4) :: Double
0.75

-- 混合类型运算
> (10 :: Int) + 3.5 -- 错误:类型不匹配
> fromIntegral (10 :: Int) + 3.5 :: Double -- 正确:13.5
  1. 在 ghci 中实验:逐行输入上述代码观察结果

  2. 查看类型信息:使用 :t 命令查看函数类型

    1
    2
    3
    4
    > :t div
    div :: Integral a => a -> a -> a
    > :t (/)
    (/) :: Fractional a => a -> a -> a
  3. 探索更多函数:使用 :info查看类型类详细信息

    1
    2
    > :info Integral
    > :info Fractional