《Haskell趣学指南》—— 第2章,第2.1节显式类型声明

第 2 章 相信类型
Haskell趣学指南
强大的类型系统是Haskell的秘密武器。
在Haskell中,每个表达式都会在编译时得到明确的类型,从而提高代码的安全性。若你写的程序试图让布尔值与数相除,就不会通过编译。这样的好处就是与其让程序在运行时崩溃,不如在编译时捕获可能的错误。Haskell中一切皆有类型,因此编译器在编译时可以得到较多的信息来检查错误。

与Java和Pascal不同,Haskell支持类型推导(type inference)。写下一个数,不必额外告诉Haskell说“它是个数”,Haskell自己就能推导出来。

在此之前,我们对Haskell类型的讲解还只是一扫而过而已,到这里不妨打起精神来,因为理解这套类型系统对于Haskell的学习是至关重要的。

2.1 显式类型声明
我们可以使用GHCi来检查表达式的类型。通过:t命令,后跟任何合法的表达式,即可得到该表达式的类型。先试一下:

ghci> :t 'a'
'a' :: Char
ghci> :t True
True :: Bool
ghci> :t "HELLO!"
"HELLO!" :: [Char]
ghci> :t (True, 'a')
(True, 'a') :: (Bool, Char)
ghci> :t 4 == 5
4 == 5 :: Bool

::读作“它的类型为”。凡是明确的类型,其首字母必为大写。'a'是Char类型,意为字符(character)类型;True是Bool类型,意为布尔(Boolean)类型;而字符串"HELLO!"的类型显示为[Char],其中的方括号表示这是个列表,所以我们可以将它读作“一组字符的列表”。元组与列表不同,每个不同长度的元组都有其独立的类型,于是(True, 'a')的类型为(Bool, Char),而('a', 'b', 'c')的类型为(Char, Char, Char)。4 == 5必返回False,因此它的类型为Bool。

同样,函数也有类型。编写函数时,给它一个显式的类型声明是一个好习惯(至于比较短的函数就不必多此一举了)。从此刻开始,我们会对我们创建的所有函数都给出类型声明。

还记得第1章中我们写的那个过滤大写字母的列表推导式吗?给它加上类型声明便是这个样子:

removeNonUppercase :: [Char] -> [Char]
removeNonUppercase st = [ c | c <- st, c `elem` ['A'..'Z']] 

这里removeNonUppercase的类型为[Char] -> [Char],意为它取一个字符串作为参数,返回另一个字符串作为结果。

不过,多个参数的函数该怎样指定其类型呢?下面便是一个将三个整数相加的简单函数。

addThree :: Int -> Int -> Int -> Int
addThree x y z = x + y + z

参数与返回类型之间都是通过->分隔,最后一项就是返回值的类型了。(在第5章,我们将讲解为何统统采用->分隔,而非Int, Int, Int -> Int之类“更好看”的方式。)

如果你打算给自己的函数加上类型声明,却拿不准它的类型是什么。那就先不管它,把函数先写出来,再使用:t命令测一下即可。因为函数也是表达式,所以:t对函数也是同样可用的。

时间: 2024-09-19 20:38:39

《Haskell趣学指南》—— 第2章,第2.1节显式类型声明的相关文章

《Haskell趣学指南》——导读

目 录 第 1 章 各就各位,预备! 第 1 章第 1 节调用函数第 1 章第 2 节小朋友的第一个函数第 1 章第 3 节列表入门第 1 章第 4 节得州区间2第 1 章第 5 节我是列表推导式第 1 章第 6 节元组 第 2 章 相信类型 第 2 章第 1 节显式类型声明第 2 章第 2 节Haskell的常见类型第 2 章第 3 节类型变量第 2 章第 4 节类型类入门 第 3 章 函数的语法 第 4 章 你好,递归 第 5 章 高阶函数 第 6 章 模块 第 7 章 构造我们自己的类型和

《Haskell趣学指南》—— 第1章,第1.1节调用函数

第 1 章 各就各位,预备!Haskell趣学指南如果你属于那种从不看前言的人,我建议你还是回头看一下本书前言的最后一节比较好.那里讲解了如何使用本书,以及如何通过GHC加载函数. 首先,我们要做的就是进入GHC的交互模式,调用几个函数,以便我们简单地体验一把Haskel.打开终端,输入ghci,可以看到如下欢迎信息: GHCi, version 6.12.3: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ..

《Haskell趣学指南》—— 第2章,第2.4节类型类入门

2.4 类型类入门 类型类(typeclass)是定义行为的接口.如果一个类型是某类型类的实例(instance),那它必实现了该类型类所描述的行为. 说得更具体些,类型类是一组函数的集合,如果将某类型实现为某类型类的实例,那就需要为这一类型提供这些函数的相应实现. 可以拿定义相等性的类型类作为例子.许多类型的值都可以通过==运算符来判断相等性,我们先检查一下它的类型签名: ghci> :t (==) (==) :: (Eq a) => a -> a -> Bool 注意,判断相等

《Haskell趣学指南》—— 第2章,第2.3节类型变量

2.3 类型变量有时让一些函数处理多种类型将更加合理.比如head函数,它可以取一个列表作为参数,返回这一列表头部的元素.在这里列表中元素的类型不管是数值.字符还是列表,都不重要.不管它具体的类型是什么,只要是列表,head函数都能够处理. 猜猜head函数的类型是什么呢?用:t检查一下: ghci> :t head head :: [a] -> a 这里的a是什么?是类型吗?想想我们在前面说过,凡是类型其首字母必大写,所以它不是类型.它其实是个类型变量(type variable),意味着a

《Haskell趣学指南》—— 第1章,第1.5节我是列表推导式

1.5 我是列表推导式 列表推导式(list comprehension)是一种过滤.转换或者组合列表的方法. 学过数学的你对集合推导式(set comprehension)概念一定不会陌生.通过它,可以从既有的集合中按照规则产生一个新集合.前10个偶数的集合推导式可以写为{2 · x | x∈N, x≤ 10},先不管语法,它的含义十分直观:"取所有小于等于10的自然数,各自乘以2,将所得的结果组成一个新的集合." 若要在Haskell中实现上述表达式,我们可以通过类似take 10

《Haskell趣学指南》—— 第1章,第1.4节得州区间2

1.4 得州区间2该怎样得到一个由1-20所有数组成的列表呢?我们完全可以用手把它们全都录入一遍,但显而易见,这并不是完美人士的方案,完美人士都用区间(range).区间是构造列表的方法之一,而其中的值必须是可枚举的,或者说,是可以排序的. 例如,数字可以枚举为1.2.3.4等.字符同样也可以枚举:字母表就是A-Z所有字符的枚举.然而人名就不可以枚举了,"John"后面是谁?我不知道. 要得到包含1-20中所有自然数的列表,只要录入[1..20]即可,这与录入[1,2,3,4,5,6,

《Haskell趣学指南》—— 第1章,第1.3节列表入门

1.3 列表入门在Haskell中,列表是一种单类型的(homogeneous)数据结构,可以用来存储多个类型相同的元素.我们可以在里面装一组数字或者一组字符,但不能把字符和数字装在一起. 列表由方括号括起,其中的元素用逗号分隔开来: ghci> let lostNumbers = [4,8,15,16,23,42] ghci> lostNumbers [4,8,15,16,23,42] 注意:在GHCi中,可以使用let关键字来定义一个常量.在GHCi中执行let a = 1与在脚本中编写a

《Haskell趣学指南》—— 第2章,第2.2节Haskell的常见类型

2.2 Haskell的常见类型接下来我们看几个Haskell中常见的基本类型,比如用于表示数.字符.布尔值的类型. Int意为整数.7可以是Int,但7.2不可以.Int是有界的(bounded),它的值一定界于最小值与最大值之间.注意:我们使用的 GHC 编译器规定 Int 的界限与机器相关.如果你的机器采用64位CPU,那么Int 的最小值一般为−263,最大值为263−1.Integer也是用来表示整数的,但它是无界的.这就意味着可以用它存放非常非常大的数(真的非常非常大!),不过它的效

《Haskell趣学指南》—— 第1章,第1.6节元组

1.6 元组元组(tuple)允许我们将多个异构的值组合成为一个单一的值.从某种意义上讲,元组很像列表.但它们却有着本质的不同.首先就像前面所说,元组是异构的,这表示单个元组可以含有多种类型的元素.其次,元组的长度固定,在将元素存入元组的同时,必须明确元素的数目. 元组由括号括起,其中的项由逗号隔开. ghci> (1, 3) (1,3) ghci> (3, 'a', "hello") (3,'a',"hello") ghci> (50, 50.4