有了前面一些基础介绍,现在我们开始介绍 Haskell
中关于类型的各种知识。
由于 Haskell
支持类型推导 (Type Inference
),允许我们不对类型进行显示声明,但对于初学者,有时我们可能依旧需要类型检查来帮助我们理解和学习。在 GHCi
中,可以使用 :t 表达式
命令来检查类型:
Haskell> :t 'a'
'a' :: Char
Haskell> :t True
True :: Bool
Haskell> :t (1, 'a')
(1, 'a') :: Num t => (t, Char)
Haskell> :t (False, 'a')
(False, 'a') :: (Bool, Char)
Haskell> :t 1 == 2
1 == 2 :: Bool
Haskell>
你可以将 ::
读作 "是一个"、"类型为"。
对于明确的类型,其首字母均为大写,例如刚才的示例中 'a'
为 Char
类型。
类似的,函数也有类型,这一点在前面函数定义一文已经有过说明。定义函数时进行类型声明是一个好的习惯。
常见类型
Int
Int
类型表示整数,它是有界的 (bounded
),也就是说这种类型的值在一个最小值与最大值范围之间,我们使用 GHC
时,这个最大值与最小值的界定根据不同的计算机会有所不同,一般的,如果你是用 64 位计算机,则 Int
值在 -263 与 263 - 1 之间。
Integer
与 Int
类似,也表示整数,但它的无界的,也就意味着这种类型的值可以极其大或及其小,远远超出 Int
表示的范围。相对的,效率要低于 Int
Float
Float
表示单精度浮点数。
Double
Double
表示双精度浮点数。两种浮点数类型的区别在于精度不同,也就是说,小数点后可用的数字位数长度不同。但相应的也会占据更多内存控件。
Bool
Bool
表示布尔 (Boolean
) 值,这种类型只有 True
与 False
两种值。
Char 与 String
Char
是字符 (Character
) 类型,表示一个 Unicode 字符。例如 'a'
。由字符组成的列表叫做字符串,即 String
,它是 [Char]
的别名,二者完全等价,但 String
更易于书写和阅读。
元组
元组也是类型,但通常它是一个统称,其实际类型取决于元素类型和数量。理论上存在无数种类型的元组,但实际中元组中元素数量最大为 62,最小为 0,即空元组 (()
),空援组也是一种类型。
类型变量
对于函数,有时需要处理多种不同类型。这不但让函数变得更加合理,增强了通用性,避免为每一种类型都定义类似函数的尴尬。举个例子,我们前面用过的 head
函数可以接受一个列表数据,不论列表元素是何种类型都返回数据。那么,我们来看看它的类型:
Haskell> :t head
head :: [a] -> a
Haskell>
刚才我们说过,类型的首字母是大写,所以此处的 a
绝不是类型。事实上,它是一个类型变量 (Type Variable
),表示 a
可以是任何类型。这样,在保证类型安全的前提下,轻松的实现了一个通用函数。
类型变量的命名允许使用多个字符,例如 somename
,但在习惯上,通常使用单个字符,例如 a
、x
、n
。
使用类型变量的函数,称为多态函数 (Polymorphic Function
)。
需要注意的是,当我们使用多个类型变量时,并不表示它们的类型一定不同,例如:
Haskell> :t fst
fst :: (a, b) -> a
Haskell>
这个例子中,a
与 b
可以是同类型,可以是不同类型,但不论怎样,它们始终是 fst
函数不同的参数。