最简单的函数
函数式编程,首先要有函数吧,来看一个最简单的函数,第一个是函数名,后面是输入变量,表达式是输出
doubleMe x=x+x
- Haskell的函数没有
return
语句,最后一句话是自然的返回值,函数都要保存为文件,文件以.hs结尾。 -
读取编写好的文件(以.hs结尾)
:l 文件名
List 数据结构
LIST基本操作
- List中各个元素的类型需要一致
- 使用 let XXX = [1,2,3,4,5]进行声明
- 字符串也是一个List
- 使用
:
添加新元素,如5 : [1,2,3,4]
将5添加到List中,可以加在之前或者之后 - 使用
!!
来获取List索引的数据,如[1,2,3,4]!!2
结果是2
-
head
返回第一个元素,tail
返回除了第一个以为的后面元素 -
last
返回最后一个元素,init
返回除最后一个元素的前面其他元素 -
length
返回list长度 -
null
检查list是否为空,为空返回True
-
reverse
反转一个List -
take
返回list的前几个元素take 2 [1,2,3,4]
-
drop
删除前几个元素 -
maximum
返回list最大值,minmum
返回最小值 -
sum
求和 -
elem
判断元素是否在list中,使用中缀表达式4 \
elem` [1,2,3,4]`
RANGE操作
- 使用
..
来生成大量连续数据,如[1..100]
- 可以使用前两个元素来表示步长,如
[1,3...100]
生成100内的奇数 - Haskell支持无限长的List,如
[1,2..]
,Haskell是惰性语言,只有在运行的时候才会去求值,所以支持无限长序列 -
cycle
用来循环一个List,生成一个无限长的List,如cysle [1,2,3]
,将生成[1,2,3,1,2,3..]
-
repeat
用来重复一个数据,并生成一个无限长List,如repeat 3
将生成[3,3,3,3,3..]
LIST的包含和过滤
Haskell是函数式编程语言,所以有一些我们之前在普通编程语言中不一样的东西,Haskell更接近数学描述,比如数学集合中的comprehension
。
List可以这么写:
[x*2 | x <- [1..10]]
这个List将返回[2,4,6,8,10,12,14,16,18,20],很显然,|
左边是表达式,右边是集合,将集合[1..10]
分别赋值给x,然后进行x*2
的运算,产生一个新的List。
对于上面那个式子,我们还可以修改一下,加一些约束,这个叫过滤
[x*2 | x <- [1..10], x*2 >= 12]
这样,返回的是[12,14,16,18,20]了,只有表达式>=12才会输出
来些实在的
好,我们来个复杂的,写一个函数,函数名为testfunc,在输入的集合中找出所有大于10并且除以3余2的所有奇数,并且将找出来的这些奇数都乘以5
testfunc abc=[ x*5 | x<-abc,x>10,x `mod` 3==2,odd x]
好,把这个保存为一个.hs结尾的文件func.hs。然后打开ghci
终端,输入:l func
,运行 testfunc [20..60],结果将输出[115,145,175,205,235,265,295]
,怎么样,简单把,你想想用命令式的编程语言(比如C语言)实现这个将如何写?呵呵
好吧,再来个难一点的,找出给定序列中的所有素数,先想想C语言怎么写,我来写个Haskell的,为了好看,我把一行的内容分开到几行了。
primeNum inNum=[x| x<- inNum,
odd x,
sum[1|_<-[y|y<-[2..x-1],
x `mod` y == 0]
]==0
]
在命令行输入:
primeNum [3..100]
输出结果为:
[3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]
对,就一行,我来解释一下,inNum是输入序列,先判断是否是奇数,然后从2到x-1重新生成一个序列赋值给_
,_
表示我们不关心值是什么,然后x取模y如果等于0,就输出一个1,否则不输出,输出的新序列求和,如果和等于0,表示没有一个x取模y等于0,表示这是一个素数,那么就把这个x输出出来。听起来挺绕口吧,仔细体会一下就明白了,你会发现函数式编程比命令行更接近我们的思维和数学模型。
Tuple(元组)数据结构
从某种意义上讲,Tuple (元组)很像 List –都是将多个值存入一个个体的容器。但它们却有着本质的不同,一组数字的 List 就是一组数字,它们的类型相同,且不关心其中包含元素的数量。
- Tuple 则要求你对需要组合的数据的数目非常的明确,它的类型取决于其中项的数目与其各自的类型。
- Tuple 中的项 由括号括起,并由逗号隔开。
- 另外的不同之处就是 Tuple 中的项不必为同一类型,在 Tuple 里可以存入多类型项的组合。
-
fst
返回元组的第一个元素fst(8,11)
,返回8 -
snd
返回元组的最后一个元素 -
zip
函数,通过两个List生成元组List,两两集合,比如zip [1,2,3] [4,5,6]
将生成[(1,4),(2,5),(3,6)]
不同长度的List通过zip组合按照短的那个List组合
来些实在的
我们有这么一个要求,在每条边都小于100的三角形中,找出所有直角三角形,并列出三条边的长度,首先,你还是想想用C语言怎么写这个程序,我还是来个haskell的。
[(a,b,c) | a<-[1..100],b<-[1..a],c<[1..b],c^2+b^2==a^2]
恩,还是一行搞定,都不需要函数了。
本教程参考了《Haskell趣学指南》,是这篇指南的学习笔记,不过参入了我自己的一些想法和总结,首先,感谢《Haskell趣学指南》的作者bonus 和大陆翻译者Fleurer和*翻译者MnO2,谢谢你们之前的工作。