Haskell/类型杂谈
到目前为止,我们只接触过整数和列表,虽然也略微提到了字符串和字符。本节将涵盖主要的类型。
理解 Haskell 的内置类型的一个重要方面是,它们并不特殊。从编译器的角度来看,它们很特殊,因为处理器有专门的操作来进行整数加法等操作。但从程序员的角度来看,它们只是普通的类型,拥有普通的函数,遵循与其他类型相同的规则。因此,本节内容很少解释如何使用这些类型或规则是什么,因为大多数情况下您已经了解了它们:如果它适用于整数,那么它也适用于字符串、布尔值和浮点数。
Haskell 有两种整数类型:Int 和 Integer。
"Integer" 是任意精度的类型:它可以保存任意大的数字,直到机器内存的限制。这就是为什么 "factorial 1000" 会给出正确答案的原因。这意味着您永远不会遇到算术溢出。另一方面,这也意味着您的算术运算相对缓慢。Lisp 用户可能认出这里的 "bignum" 类型。
"Int" 是更常见的 32 或 64 位整数。实现方式可能有所不同,但保证至少为 30 位。
Haskell 也有两种浮点类型:Float 和 Double。它们的行为类似于 C 中的对应类型。
所有常见的运算符都存在,还有一些额外的运算符。
- 旁注:Haskell 的数字类型在类型类的复杂层次结构中相互关联,这些类型类将在后面介绍。本页的目的是让您能够进行普通的算术运算,而不会被类型系统绊倒。
有三个 "幂运算" 运算符,它们的工作方式不同,接受的类型也不同。
- **
- 接受两个浮点数,使用对数来计算幂。
- ^^
- 接受一个分数(例如浮点数或比例,后面会讲到)并将其提升到正或负整数幂。
- ^
- 接受任何数字类型并将其提升到正整数幂。
从整数类型(Int 或 Integer)转换为其他任何类型是通过 "fromIntegral" 完成的。目标类型是自动推断的。例如
n :: Integer n = 6 x :: Float x = fromIntegral n m :: Int m = 7 y :: Double y = fromIntegral m
将定义 x 为 6.0,y 为 7.0。
整数除法有点复杂。如果您对整数使用普通的 "/" 运算符,那么您会收到错误消息(虽然表达式 "4/3" 可以工作,因为 Haskell 会在必要时将文字整数提升为浮点数)。相反,整数除法是使用一组命名的运算符完成的。
Haskell 在运算符方面有一个巧妙的技巧:您可以将任何接受两个参数的函数用反引号括起来,使其像运算符一样使用。因此,以下两行表示完全相同的意思
d = 7 `div` 3 d = div 7 3
考虑到这一点,以下是整数除法运算符
- quot
- 返回两个数字的商。这是除法运算的结果,然后被截断为零。
- rem
- 返回商的余数。
- div
- 类似于 "quot",但向下舍入到负无穷。
- mod
- 返回两个数字的模。这类似于余数,但在 "div" 返回负数时有不同的规则。
只要 y 不是负数,以下两个方程始终成立
(x `quot` y)*y + (x `rem` y) == x (x `div` y)*y + (x `mod` y) == x
就像您可以将接受两个参数的函数转换为运算符一样,您也可以将运算符转换为接受两个参数的函数:只需将其放在括号中。因此,以下两行表示相同的意思
(+) 3 4 3 + 4
这也可以对任何 "不完整的" 运算符应用进行
(3+) 4 (+4) 3 -- not 3 (+4)
Haskell 具有布尔类型Bool,有两个值True和False。该类型上还定义了两个运算符Bool类型&&和||.
数字、字符和字符串可以使用通常的比较运算符进行比较,以生成一个 Bool 值
- ==
- 相等。
- /=
- 不相等。
- <=
- 小于或等于。
- >=
- 大于或等于。
- <
- 小于。
- >
- 大于。
(当您了解到 类型类 时,请注意,相等运算符 (==, /=) 是类型类的一部分Eq,比较运算符 (<=, >=, <, >) 是类型类的一部分Ord.)
Haskell 有一个 "if-then-else" 子句,但由于 Haskell 是一种函数式语言,它更类似于 C 中的 "? :" 运算符:它不是 "执行" "then" 子句或 "else" 子句,而是整个表达式计算出其中一个子句的值。例如,阶乘函数可以写成
factorial n = if n <= 0 then 1 else n * factorial (n-1)
一个if表达式的语法是
if <condition> then <true-value> else <false-value>
如果条件为 True,那么 "if" 的结果就是真值,否则就是假值。