03 类型和类型类

类型

Haskell 是强类型和静态类型的,所有的数据都有明确的类型

静态类型的好处

  • 编译期间就可以发现很多类型导致的错误
  • 支持类型推导

表达式的类型

  • 使用 :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

函数的类型

函数也有明确的类型,包括参数的类型和返回值的类型。

比如前面那个过滤大写字母的函数,输入一个字符串,输出一个字符串,类型如下

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

注意: [Char]String 是等价的

多个参数的函数,类型之间用 -> 分隔,最后一项是输出类型

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

几种常见的基本类型

类型 说明
Int 32 位整数,有边界
Integer 大整数,没有边界
Float 单精度浮点数,精度稍差
Double 双精度浮点数,精度较高
Bool 布尔值
Char 字符类型

类型变量

有的时候,函数在定义的时候参数的类型不能确定,等到使用时参数传入后才可以确定类型,这时可以用一个变量代替参数类型。

比如处理列表的 head 函数。列表可以是任意类型的列表,返回值只要和列表中元素的类型一致即可。

ghci> :t head  
head :: [a] -> a

类型变量都使用单个小写字母

类型类入门

TypeClasses 叫类型类,他是对类型约束和规范,他要求类型必须满足某些规格,有点类似接口。

类型被某种 TypeClasses 约束后,和这种 TypeClasses 相关的函数就可以处理被其约束的类型,

下面是 == 函数的类型声明,该函数的参数被 Eq 约束,说明这个参数可以被 Eq 相关的函数所处理

ghci> :t (==)
(==) :: (Eq a) => a -> a -> Bool

读作: 相等函数取两个相同类型的值作为参数,传回一个布尔值。两个参数的类型必须符合 Eq 类型类的约束

Eq 规定了判断相等性的规范,凡是能够比较相等性的类型都必须被 Eq 类约束,比如数字、字符、字符串等等

ghci> 5 == 5
True

ghci> 5 /= 5
False

ghci> 'a' == 'a'
True

ghci> "Ho Ho" == "Ho Ho"
True

ghci> 3.432 == 3.432
True

elem 函数中,因为其参数要使用 == ,所以也被 Eq 约束

ghci> :t elem
(Eq a)=>a->[a]->Bool

基本的类型类

Eq

任何需要使用相等性判断的类型,即希望该类型能够被 ==/= 等函数处理,都要受 Eq 约束

Ord

需要比较大小,能够被 <, >, <=, >=, compare 等相关函数处理的类型,都受它约束

注意:要成为 Ord 的成员,首先需要加入 Eq

ghci> "Abrakadabra" < "Zebra"  
True  

ghci> "Abrakadabra" `compare` "Zebra"  
LT  

ghci> 5 >= 2  
True  

ghci> 5 `compare` 3  
GT
Show

show 函数可以将一个数据对象转换成字符串

任何需要能转换成字符串,并能够被 show 函数处理的的类型,都受它约束

ghci> show 3  
"3"  

ghci> show 5.334  
"5.334"  

ghci> show True  
"True"
Read

read 函数可以将字符串转换成一个数据对象,他是 show 函数的反函数

ReadShow 正好相反,任何类型想要获取从字符串转换成对象的能力,即能够被 read 函数处理,都受它约束

ghci> read "True" || False  
True  

ghci> read "8.2" + 3.8  
12.0 

ghci> read "5" - 2  
3  

ghci> read "[1,2,3,4]" ++ [3]  
[1,2,3,4,3]

转换时须明确类型

需要注意的是,如果字符串转换的类型不能推断,则需要明确指定,否则会报错

下面代码中,4 既可以转换成 Int 类型,也可以转换成 Integer Float 类型,因为没有明确指定,编译器会报错

ghci> read "4"  
< interactive >:1:0:  
    Ambiguous type variable `a' in the constraint:  
      `Read a' arising from a use of `read' at <interactive>:1:0-7  
    Probable fix: add a type signature that fixes these type variable(s)

下面明确指定类型

ghci> read "5" :: Int  
5  

ghci> read "5" :: Float  
5.0  

ghci> (read "5" :: Float) * 4  
20.0  

ghci> read "[1,2,3,4]" :: [Int]  
[1,2,3,4]  

ghci> read "(3, 'a')" :: (Int, Char)  
(3, 'a')

Enum

连续类型,有前置和后继,能够被 succpred 等函数处理。

相关类型有 (), Bool, Char, Ordering, Int, Integer, Float 和 Double

ghci> ['a'..'e']  
"abcde"  

ghci> [LT .. GT]  
[LT,EQ,GT]  

ghci> [3 .. 5]  
[3,4,5]  

ghci> succ 'B'  
'C'
Bounded

有上下边界的类型,能够被 minBoundmaxBound 等函数处理

ghci> minBound :: Int  
-2147483648  

ghci> maxBound :: Char  
'\1114111' 

ghci> maxBound :: Bool  
True  

ghci> minBound :: Bool  
False

注意,如果元组中的分量都是有边界的,那么元组也是有边界的

ghci> maxBound :: (Bool, Int, Char)  
(True,2147483647,'\1114111')

Num

如果你的类型需要进行四则运算,即能够使用 + - * / 等相关函数,则应该被 Num 约束

下面的代码说明, * 要求的参数类型虽然还不确定,但是只要符合 Num 规范就可以,因此传给他 Int Float 都可以

ghci> :t (*)  
(*) :: (Num a) => a -> a -> a

注意,乘号两边的数字类型必须一致,否则会报错,比如

(5 :: Int) * (6 :: Integer)
Integral

对所有整数的规范

Floating

对所有浮点数的规范

重要函数 fromIntegral

这个函数会将一个对象的约束条件从 Integral 转换成 Num,受 Num 约束的数是更通用的数,可以使用更多的函数

fromIntegral :: (Num b, Integral a) => a -> b

历史问题

由于历史原因,某些函数会返回整数类型,而不是通用数字类型。这时候如果用返回值和其他数字类型运算会出错。

举例来说,length 函数的型别声明为:

length :: [a] -> Int

如果用 length 的返回值,给它加一个浮点数 3.2 就会报错,因为这是将浮点数和整数相加。

这时候就需要

fromIntegral (length [1,2,3,4]) + 3.2

</br>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,231评论 0 4
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,622评论 18 399
  • 观察一个成人 不是听,看他说了什么 而是观察他的行事方式 一个自私的幼体成长为大人,必定掌握了各种达到目的的手段,...
    黑寡妇的茉莉阅读 341评论 0 0
  • 《读在河大》 ――记距离第一次放寒假还有半个月的时间 每天都走在河大的...
    张双婷阅读 331评论 2 0