chapter2 类型和函数

Haskell的类型系统

  • 强类型:类型转换必须显示使用类型转换函数。
  • 静态:不是python这种动态语言。java这样的编译时期就能发现类型不正确的表达式。Haskell提供的typeclass机制提供了大部分动态类型的特点。
  • 可以通过自动推导得出

一些常用的基本类型

  • Char: 单个Unicode字符
  • Bool:一个布尔逻辑值。只有2个值。 True和False
  • Int:带符号的定长整数
  • Integer: 不限长度的带符号整数。对Integer的计算不会造成溢出。因此使用Integer的计算结果更可靠。
  • Double:浮点数,长度由机器决定,通常是64位。
    :: 这个符号用来标识类型.例如:: T 就是像Haskell表示,exp的类型是T. :: T 就是exp的类型签名。如果一个表达式没有显示地指名类型,它的类型就通过自动推导决定。
Prelude> :type 'a'
'a' :: Char

Prelude> 'a'            -- 自动推导
'a'

Prelude> 'a' :: Char    -- 显式签名
'a'

类型签名必须正确。

Prelude> 'a' :: Int     -- 试图将一个字符值标识为 Int 类型

<interactive>:7:1:
    Couldn't match expected type `Int' with actual type `Char'
    In the expression: 'a' :: Int
    In an equation for `it': it = 'a' :: Int

调用函数

要调用一个函数,首先写出它的名字.后面接函数的参数

Prelude> odd 3
True

Prelude> odd 6
False

注意.函数的参数不需要括号来包围,参数与参数直接直接通过空格来隔开.

Prelude> compare 2 3
LT

Prelude> compare 3 3
EQ

Prelude> compare 3 2
GT

函数应用的优先级比操作符要高.

Prelude> (compare 2 3) == LT
True

Prelude> compare 2 3 == LT
True

复合数据类型:列表和元组

复合类型通过其他类型构建得出.Haskell中最常用的是复合类型数据是列表跟元组.

  • String 是[char]的别名,[Char]表示由Char类型组成的列表.
    因为列表中的值可以是任意类型,所以列表是类型多态的.当编写带有多态类型的代码时,需要使用类型变量.这些类型变量用小写字母开头,作为一个占位符,最终被一个具体的类型替代(有点像java的泛型)
    [a] 表示一个'类型为a的列表'
  • 元组:跟列表的两个属性相反,元组长度固定,但可以包含不同类型的值.
    Haskell 有一个特殊的类型(),这种类型只有一个值(),它的作用相当于包含零个元素的元组,类似于C语言中的void:
Prelude> :t ()
() :: ()

元组通常用于以下两个地方:

  • 如果一个函数需要返回多个值,可以将这些值包装到一个元组中,然后返回元组作为函数的值.
  • 当需要使用定长容器,又没必要使用自定义的类型时,就可以使用元组来对值进行包装.

处理列表和元组的函数

  • take和drop.接受两个参数,一个数字n和一个列表l.
Prelude> take 2 [1, 2, 3, 4, 5]
[1,2]
Prelude> drop 2 [1, 2, 3, 4, 5]
[3,4,5]
  • fst,snd接受一个二元组作为参数,返回该元组的第一个和第二个元素。
Prelude> fst (1, 'a')
1

Prelude> snd (1, 'a')
'a'

将表达式传给函数

Haskell函数应用是左关联的。比如说,表达式a b c d 等同于(((a b) c) d)。要将一个表达式用作另一个表达式的参数。必须显式的使用括号来包围它。

Prelude> head (drop 4 "azety")
'y'

函数类型

使用 :type命令可以查看函数的类型[缩写形式为:t]

Prelude> :type lines
lines :: String -> [String]

通过类型签名显示,lines函数接受单个字符串,并返回包含字符串值的列表。

纯度

副作用:假设有某个函数,它读取并返回某个全局变量,如果程序中的其他代码可以修改这个全局变量,那么这个函数的返回值就取决于这个全局变量在某一时刻的值。
Haskell的函数在默认情况下都是无副作用的。函数的结果只取决于显式传入的参数。
带副作用的函数称为“不纯(impure)函数”。不带副作用的函数称为“pure函数“
从类型签名可以看出一个Haskell函数是否带有副作用 -不纯的函数类型签名都以IO开头:

Prelude> :type readFile
readFile :: FilePath -> IO String

Haskell源码,以及简单函数的定义

ghci只支持Haskell特性的一个非常受限的子集。因此,将代码写在源码文件里。
Haskell源码通常以.hs作为后缀.我们创建一个add.hs文件,并将以下定义添加到文件中:

-- file: ch02/add.hs
add a b = a + b

=号左边的add a b是函数名和函数参数,而右边的a+b则是函数体,符号=表示将左边的名字(函数名和函数参数)定义为右边的表达式(函数体)。
将add.hs保存后,可以在ghci里通过: load (缩写为:l)载入。然后直接调用add函数即可。
注意,Haskell里一个函数就是一个单独的表达式,而不是一组陈述。所以不适用return关键字来返回函数值。

变量

  • 在Haskell中,一旦变量绑定了某个表达式,name这个变量的值就不会改变,我们总能用这个变量来指代它所关联的表达式,而且每次都会得到同样的结果
  • 在声明式语言中,变量的值可能无时无刻都处在改变当中。

条件求值

Haskell中的if表达式。
首先看自己实现的一个drop函数

myDrop n xs = if n <= 0 || null xs
              then xs
              else myDrop (n - 1) (tail xs)

if 关键字引入了一个带有三个部分的表达式:

  • 跟在if之后的是一个Bool类型表达式,是if的条件部分
  • then 之后的是另一个表达式。这个表达式表示在if条件为
    True时执行
  • else之后的是另一个表达式,在条件部分是False时被执行。
  • 跟在thenelse之后的表达式称为"分支".不同分支之间的类型必须相同.如果是if True then 1 else "foo"这样的表达式会产生错误,因为两个分支的类型并不相同。

通过示例了解求值

惰性求值

isOdd n = mod n 2 == 1

一般而言,使用上面的isOdd函数计算isOdd (2+1),都是先计算2+1 = 3 然后在用isOdd的函数定义来进行判断.
但是在Haskell中.并不需要先计算出(2+1).只用把这个表达式存在块中.当这个子表达式的值真正被需要时才进行计算.

Haskell里的多态.

观察last函数.这个函数返回列表中的最后一个元素,不管列表中元素的类型是int或者string.
last函数签名:

last :: [a] -> a

a可以指代任意类型.

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

推荐阅读更多精彩内容