数值类型
交互式地探索 Haskell 的一些基本数值类型。
Haskell 中最核心的两个概念是 类型 和 函数。
- 类型 是具有相似行为的值的集合,例如数字或字符串。
- 函数 可以用来将一种类型的值映射到另一种类型。
在本节课中,我们将学习 Haskell 中一些最基本的数值类型,以及作用于这些类型的预定义函数。
GHCI
本课中的示例将使用 ghci,这是随 Glasgow Haskell 编译器(GHC)一起提供的交互式 Haskell 解释器。ghci 是一种所谓的 REPL,它会:
- R 读取你的输入(一个 Haskell 表达式)
- E 评估该表达式
- P 打印结果
- L 循环(即你可以反复输入表达式)
你可以使用下面的工具来输入本课的示例,或者直接在 ghci 中进行尝试。
数字
在 GHCI 中,你应该看到类似这样的提示符:
1GHCi, version 8.8.3: https://www.haskell.org/ghc/ :? for help 2Prelude>
我们从一些简单的算术运算开始:
1Prelude> 1 + 2 23 3Prelude> 5 * (7 - 1) 430 5Prelude> 3 / 2 61.5
数值表达式按我们预期的方式进行计算。第一个例子中,1 和 2 是数值类型的值,+ 是一个将两个数合并得到它们和的函数。
Haskell 中有多种数值类型。最重要的包括:
Int用于整数(通常是 64 位),如5、0、-32。Integer用于任意大小的整数(在其他语言中常称为“大整数”)。Double用于 64 位浮点数,如1.5、-0.007。
运算符 +、*、- 可以用于上述任意类型,但 / 不适用于整数。
类型推断与类型注解
请注意,在上面的表达式中,我们无需指定数字的类型。这是因为 Haskell 使用 类型推断 自动确定表达式的类型。这可以通过检查表达式中出现的值和函数来完成。例如,由于除法运算符 / 不能用于整数之间,因此 3 / 2 的类型不可能是 Int。
不过,我们也可以显式地 标注 值的类型。例如,可以这样写:
1Prelude> (1 :: Int) + (2 :: Int) 23
一般来说,类型注解是可选的,但在值的类型不明确时,添加类型注解可以使代码更清晰。
让我们用类型注解来演示 / 无法作用于整数:
1Prelude> (3 :: Int) / (2 :: Int) 2 3<interactive>:12:1: error: 4 • No instance for (Fractional Int) arising from a use of ‘/’ 5 • In the expression: (3 :: Int) / (2 :: Int) 6 In an equation for ‘it’: it = (3 :: Int) / (2 :: Int)
事实上,尝试将一个 Int 除以另一个 Int 会产生 类型错误。错误信息解释了原因:Haskell 期望 / 的参数是分数类型,但实际传入的是整数。
通常情况下,我们只能使用算术运算符组合相同类型的值,否则会出现类型错误。
1Prelude> (2 :: Int) + (3 :: Double) 2 3<interactive>:8:15: error: 4 * Couldn't match expected type `Int' with actual type `Double' 5 * In the second argument of `(+)', namely `(3 :: Double)' 6 In the expression: (2 :: Int) + (3 :: Double) 7 In an equation for `it': it = (2 :: Int) + (3 :: Double)
类型错误由编译器在称为 类型检查 的编译阶段发现,该阶段也负责类型推断。包含类型错误的 Haskell 程序无法成功编译。类型检查的优势在于,潜在的错误可以在编译阶段被发现,而不会导致程序运行时出现错误。
Quiz
为什么表达式 3.5 + (3 :: Int) 会产生类型错误?