交互式环境中的简单测试
设置命令行提示符:
set prompt "ghci>"
四则运算
ghci> 2 + 15
17
ghci> 49 * 100
4900
ghci> 1892 - 1472
420
ghci> 5 / 2
2.5
ghci>
括号改变优先级
ghci> (50 * 100) - 4999
1
ghci> 50 * 100 - 4999
1
ghci> 50 * (100 - 4999)
-244950
布尔运算
ghci> True && False
False
ghci> True && True
True
ghci> False || True
True
ghci> not False
True
ghci> not (True && True)
False
相等性判断
ghci> 5 == 5
True
ghci> 1 == 0
False
ghci> 5 /= 5
False
ghci> 5 /= 4
True
ghci> "hello" == "hello"
True
类型错误
传给函数的参数的类型必须符合要求,否则会报错
ghci> 5+"llama"
No instance for (Num [Char])
arising from a use of `+' at :1:0-9
Possible fix: add an instance declaration for (Num [Char])
In the expression: 5 + "llama"
In the definition of `it': it = 5 + "llama"
调用函数
函数调用不需要括号,参数之间用空格分开
ghci> succ 8
9
ghci> min 9 10
9
ghci> min 3.4 3.2
3.2
ghci> max 100 101
101
函数的高优先级
函数是右结合的
ghci> succ 9 + max 5 4 + 1
16
ghci> (succ 9) + (max 5 4) + 1
16
自定义函数
Haskell 中的自定义函数和数学中的函数非常类似,例如 f(x) = x + x
下面定义的函数会将一个数乘以 2
doubleMe x = x + x
保存并载入
保存为 baby.hs
文件,然后用 :l
指令载入
ghci> :l baby
[1 of 1] Compiling Main ( baby.hs, interpreted )
Ok, modules loaded: Main.
ghci> doubleMe 9
18
ghci> doubleMe 8.3
16.6
分支表达式 if ... then ... else ...
在 **Haskell **中
if
语句是一个表达式,因此是有返回值的- 必须有
eles
语句 - 两个分支返回的数据类型必须相同,否则报错
doubleSmallNumber x = if x > 100
then x
else x*2
因为 if
语句是个表达式,最终可以简化成一个值,因此可以用在任何地方
doubleSmallNumber' x = (if x > 100 then x else x*2) + 1
函数的命名规范
- 函数名中可以使用单引号
- 函数名首字母必须小写
- 没有参数(变量)的函数,相当于定义了一个常量,他的值不可修改
List 入门
List 本质上就是个序列,和其他动态语言不同,序列中的项是同一种类型
注意:在交互式环境下,需要用
let
定义变量
ghci> let lostNumbers = [4,8,15,16,23,48]
ghci> lostNumbers
[4,8,15,16,23,48]
++
合并运算
[1,2,3,4] ++ [9,10,11,12] == [1,2,3,4,9,10,11,12]
:
在列表头上添加一个元素,速度很快
'A' : " SMALL CAT" == "A SMALL CAT"
5:[1,2,3,4,5] == [5,1,2,3,4,5]
[]
空列表
空列表是列表中的最内层元素,列表实际上是一系列列连接运算的语法糖
[1,2,3] == 1:2:3:[]
-
!!
索引列表中的元素,注意不要超出边界
"Steve Buscemi" !! 6 == 'B'
[9.4,33.2,96.2,11.2,23.25]!! 1 == 33.2
列表中的列表
列表中可以嵌套列表,但是子列表的类型必须相同
ghci> let b = [[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3]]
ghci> b
[[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3]]
ghci> b ++ [[1,1,1,1]]
[[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3],[1,1,1,1]]
ghci> [6,6,6]:b
[[6,6,6],[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3]]
ghci> b !! 2
[1,2,2,3,4]
列表比较大小
列表可以比较大小,比较的时候会对其中的元素依次进行比较
ghci> [3,2,1] > [2,1,0]
True
ghci> [3,2,1] > [2,10,100]
True
ghci> [3,4,2] > [3,4]
True
ghci> [3,4,2] > [2,4]
True
ghci> [3,4,2] == [3,4,2]
True
head
取出列表的头
head [5,4,3,2,1] == 5
tail
取出除了头以外的部分
tail [5,4,3,2,1] == [4,3,2,1]
last
取出列表的尾
last [5,4,3,2,1] == 1
init
取出除了尾以外的部分
init [5,4,3,2,1] == [5,4,3,2]
注意:上面四个函数处理空列表会出错
ghci> head []
*** Exception: Prelude.head: empty list
length
返回一个 List 的长度
ghci> length [5,4,3,2,1]
5
null
检查一个 List 是否为空
ghci> null [1,2,3]
False
ghci> null []
True
reverse
将一个 List 反转
ghci> reverse [5,4,3,2,1]
[1,2,3,4,5]
take
返回列表的前几个元素
- 若是取超过 List 长度的元素个数,只能得到原 List
- 若
take 0
个元素,则会得到一个空 Lis!
ghci> take 3 [5,4,3,2,1]
[5,4,3]
ghci> take 1 [3,9,3]
[3]
ghci> take 5 [1,2]
[1,2]
ghci> take 0 [6,6,6]
[]
drop
删除列表的前几个元素
ghci> drop 3 [8,4,2,1,5,6]
[1,5,6]
ghci> drop 0 [1,2,3,4]
[1,2,3,4]
ghci> drop 100 [1,2,3,4]
[]
maximum
返回列表中最大的元素
minimun
返回列表中最小的元素
ghci> minimum [8,4,2,1,5,6]
1
ghci> maximum [1,9,2,3,4]
9
sum
返回列表 中所有元素的和
product
返回列表中所有元素的积
ghci> sum [5,2,1,6,3,2,5,7]
31
ghci> product [6,2,1,2]
24
ghci> product [1,2,5,6,7,9,2,0]
0
elem
判断一个元素是否在列表中
ghci> 4 `elem` [3,4,5,6]
True
ghci> 10 `elem` [3,4,5,6]
False
使用 Range
Range
可以定义一个有序序列
所谓序列类似于数学上的数列,可以递增或者递减
[1..20] == [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
['a'..'z'] == "abcdefghijklmnopqrstuvwxyz"
['K'..'Z'] == "KLMNOPQRSTUVWXYZ"
可以指定序列的间距
[2,4..20] == [2,4,6,8,10,12,14,16,18,20]
[3,6..20] == [3,6,9,12,15,18]
不要使用浮点数创建序列,不精确
[0.1, 0.3 .. 1] == [0.1,0.3,0.5,0.7,0.8999999999999999,1.0999999999999999]
惰性
cycle
创建一个无限循环的序列
take 10 (cycle [1,2,3]) == [1,2,3,1,2,3,1,2,3,1]
take 12 (cycle"LOL ") == "LOL LOL LOL "
repeat
创建一个无限长度的序列
take 10 (repeat 5) == [5,5,5,5,5,5,5,5,5,5]
列表解析
列表解析本质上就是代数上的集合变换。下面将序列中的元素翻倍
[x*2 | x <- [1..10]] == [2,4,6,8,10,12,14,16,18,20]
条件过滤
可以给集合设定过滤条件,符合条件的项才会进入新的列表
下面条件只将序列中翻倍后能够大于 12
的元素进行翻倍后进入新的序列
[x*2 | x <- [1..10], x*2 >= 12] == [12,14,16,18,20]
取 50
到 100
之间所有除 7
余 3
的元素
[ x | x <- [50..100], x `mod` 7 == 3] == [52,59,66,73,80,87,94]
注意:条件由逗号分隔
多条件过滤
可以设置多个过滤条件
[ x | x <- [10..20], x /= 13, x /= 15, x /= 19] == [10,11,12,14,16,17,18,20]
多个列表解析
将多个序列变换成一个序列,每个 <-
符号处理一个序列
- 注意:过滤条件可以使用多个解析变量进行运算
- 将两个变量的运算结果进入新序列
[ x*y | x <-[2,5,10], y <- [8,10,11], x*y > 50] == [55,80,100,110]
全排列
解析多个序列的时候是一种全排列组合
ghci> let nouns = ["hobo","frog","pope"]
ghci> let adjectives = ["lazy","grouchy","scheming"]
ghci> [adjective ++ " " ++ noun | adjective <- adjectives, noun <- nouns]
["lazy hobo","lazy frog","lazy pope","grouchy hobo","grouchy frog", "grouchy pope","scheming hobo",
"scheming frog","scheming pope"]
用列表解析实现一个 length
函数
如果不关心列表中的元素是什么,可以用下划线代替
length' xs = sum [1 | _ <- xs]
过滤大写字母
就是用条件过滤将大写字母过滤出来
注意:这里使用了
\
elem` ` 函数
removeNonUppercase st = [ c | c <- st, c `elem` ['A'..'Z']]
ghci> removeNonUppercase "Hahaha! Ahahaha!"
"HA"
ghci> removeNonUppercase "IdontLIKEFROGS"
"ILIKEFROGS"
嵌套列表解析
解析出来的项如果是个列表,可以再次解析
ghci> let xxs = [[1,3,5,2,3,1,2,4,5],[1,2,3,4,5,6,7,8,9],[1,2,4,2,1,6,3,1,3,2,3,6]]
ghci> [ [ x | x <- xs, even x ] | xs <- xxs]
[[2,2,4],[2,4,6,8],[2,4,2,6,2,6]]
元组
列表像是一个数组,而元组更像是向量,其中每个元素都是一个分量
元组有自己的数据类型,分量的数目和类型决定了元组的类型。向下面这样的列表是错误的,因为其中的元组类型不一样
[(1,2),(8,11,5),(4,5)]
Couldn't match expected type `(t, t1)'
against inferred type `(t2, t3, t4)'
In the expression: (8, 11, 5)
In the expression: [(1, 2), (8, 11, 5), (4, 5)]
In the definition of `it': it = [(1, 2), (8, 11, 5), (4, 5)]
元组比较大小
Prelude> (1,2,3)>(2,3,4)
False
没有一元组
最短的元组也应该有两个分量,叫做二元组或者序对。
一元组没有意义,就是数据本身
Prelude> (2)
2
Prelude> (1,2)
(1,2)
取二元组的分量
-
fst
取出序对中的第一个分量 -
snd
取出序对中的第二个分量
注意:
fst
snd
这两个函数只能处理二元组,不能处理多元组
ghci> fst (8,11)
8
ghci> fst ("Wow", False)
"Wow"
ghci> snd (8,11)
11
ghci> snd ("Wow", False)
False
zip
函数
zip
函数可以将两个列表中的元素组合起来,变成一个二元组列表
注意:如果用列表解析处理,就变成了全排列,或许可以用
map
?
ghci> zip [1,2,3,4,5] [5,5,5,5,5]
[(1,5),(2,5),(3,5),(4,5),(5,5)]
ghci> zip [1 .. 5] ["one", "two", "three", "four", "five"]
[(1,"one"),(2,"two"),(3,"three"),(4,"four"),(5,"five")]
不同长度的列表也能组合,以较短的为标准
ghci> zip [1..] ["apple", "orange", "cherry", "mango"]
[(1,"apple"),(2,"orange"),(3,"cherry"),(4,"mango")]
通过列表解析构造元组的列表
问题:找出所有边长都小于等于 10
,周长等于 24
的直角三角形
注意:这里的解析条件使用了三个解析变量进行运算
ghci> let rightTriangles' =
[(a,b,c) | c <- [1..10], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2, a+b+c == 24]
ghci> rightTriangles'
[(6,8,10)]