本节最重要的是map和filter。他们的作用等价于list comprehension,如[x*2 | x <- [1,2..10] ]左边是map,右边是filter。
foldl也比较重要,类似reduce函数,规约计算
一 高阶函数
所谓高阶函数,即输入输出均为函数的函数。
1匿名函数(不常用,一般都用有名字的)
语法格式为(\para1..paran->function_body)
例如,连接字符串(\x->x++"world")"hello"
2 map
map可以讲一个函数映射到一个列表上
3filter,foldl,foldr
filter 对于列表中每个元素测试。如filter odd[1,2,3]
fold 一个fold取一个二元函数,一个初始值(我喜欢管它叫累加值)和一个需要fold(折叠)的list。这个二元函数有两个参数,即累加值和list的首项(或尾项),返回值是新的累加值。然后,以新的累加值和新的list首项调用该函数,如是继续。到list遍历完毕时,只剩下一个累加值,也就是最终的结果
foldl 左折叠函数 参考自 http://www.yeeyan.org/articles/view/ssword/50295
首先看下foldl函数,也叫做左折叠。它从list的左端开始折叠,用初始值和list的头部调用这二元函数,得一新的累加值,并用新的累加值与list的下一个元素调用二元函数。如是继续。
我们再实现下sum,这次用fold替代那复杂的递归:
sum' :: (Num a) => [a] -> a
sum' xs = foldl (acc x -> acc + x) 0 xs
ghci> sum' [3,5,2,1]
11
我们深入看下fold的执行过程:acc x-> acc + x 是个二元函数,0是初始值,xs是待折叠的list。一开始,累加值为0,当前项为3,调用二元函数0+3得3,作新的累加值。接着来,累加值为3,当前项为5,得新累加值8。再往后,累加值为8,当前项为2,得新累加值10。最后累加值为10,当前项为1,得11。恭喜,你完成了一次折叠(fold)!
foldr右折叠函数 (从右边开始)二 偏应用函数和柯里化
一言以蔽之:每个haskell函数只有一个参数。代码中的多参数函数实际上使用柯里化机制自动变成单参数函数。(programmer dont care)
三 惰性求值
惰性求值是为了构建无穷列表。使用head(得到第一个),drop(去掉前几项),take(得到前几项)
例如 myrange start step=start:(myrange start+step step)
take 10 (myrange 10 1)
四 附:列表和元组的操作函数
参考自:http://wizardmin.com/2011/05/haskell_basic_1/
(0) map,filter,flodr,foldl参考上边
(1)连接 ++ :
++
ghci> [1,2,3] ++ [6,7,8]
[1,2,3,6,7,8]
:
5:[1,2,3,4]
[5,1,2,3,4]
(2)!! 访问列表元素
ghci> [1,2,3,4,5,6,7] !! 1
2
(3)多维
ghci> let b = [[1,2,3,4],[5,3,3,3],[1,2,3]]
ghci> [6,6,6] : b
[[6,6,6],[1,2,3,4],[5,3,3,3],[1,2,3]]
但不能这样定义:b =[1,2,[3,4]],类型不一样
(4)列表对比关系
采用<, >,==等根据字典序进行比较
ghci > [3,2,1] > [2,1,0]
True
(5)其他操作
head 获取列表第一个元素
ghci> head [[1,2,3],[4,5,5],[2,3,5]]
[1,2,3]
tail 取列表中除了第一个元素的其他元素
ghci> tail [1,2,3,4,5]
[2,3,4,5]
last 取列表最后一个元素(与head对应)
init 取列表中除了最后一个元素的其他元素(与tail对应)
length 列表长度(不递归计算)
ghci> length [[1,2,3], [2,1,3], [1,3,5]] 3
null 检测列表是否为空
reverse 反转列表
take 从列表头开始取指定个数的元素
ghci> take 3 [5,4,3,2,1]
[5,4,3]
ghci> take 8 [5,4,3,2,1]
[5,4,3,2,1]
ghci> take 0 [5,4,3,2,1]
[]
drop 跳过列表头指定个数的元素的列表
ghci> drop 3 [5,4,3,2,1]
[2,1]
maximum 取列表最大的元素
minimum 娶列表最小的元素
sum 列表总和
product 列表乘积
elem 判断元素是否属于列表(一般当作中缀型使用)
ghci> 3 `elem` [3,4,5,6]
True
zipwtith 对两个列表的对应位置元素进行操作
例如 zipWith (+) [1,2,3] [1,2,3]
[2,4,6]
(6)枚举
在Haskell,由1到10的数字组合的列表不需列出所有数字
ghci> [1..10]
[1,2,3,4,5,6,7,8,9,10]
(7)集合
类似高等数据的集合
例如:数学定义{2 · x| x ∈ N, x ≤ 10}
ghci> [x * 2 | x <- [1..10]]
[2,4,6,8,10,12,14,16,18,20]
竖线(|)前是集合输出,竖线后是元素的定义
ghci> [x | x <- [50..100], x `mod` 7 == 0]
[56,63,70,77,84,91,98]
元组
元组是把不同类型的元素存储到一个值的方式,不同长度(元素个数不一样)的元组是定义为不同类型的,相同长度但对应的元素类型不一样的元素也是定义为
不同类型。例如:[(1,2),(8,11,5)]或[(1,2),(1,'a')]是错误的。
对(长度为2的元组)
长度为2的元组比较常用,可以由fst和snd函数操作(不能操作长度不为2的元组)
ghci> fst (8, 11)
8
ghci> snd (8, 11)
11
zip函数将两个列表组合成对,变成元组的列表
ghci> zip [1,2,3,4] [5,5,5]
[(1,5),(2,5),(3,5)](多余的元素会被删掉)
本文参考自 《七周七语言》。
课后题答案:
--8.3.6
qsort []=[]
qsort (h:t)=(qsort(filter (<h) t) )++(num (h:t)) ++(qsort(filter (>h) t))
num (h:t)=filter (==h) (h:t)
qsort2 compare1 []=[]
qsort2 compare1 (h:t)=(qsort2 compare1 (filter (compare1 h) t))++(num (h:t))++(qsort2 compare1 (filter (\x->(x/=h)&&(not(compare1 h x))) t ))
compare1 a b=a<b
--4
--belazy1 x=[x]++(belazy1 x+2)
belazy1 x=x:(belazy1 (x+2))
belazy2 y=y:(belazy2 (y+4))
belazy x y=(zipWith (+) (belazy1 x) (belazy2 y))
--5
cfun x=x/2
--6
func6 0 y=y
func6 x 0=x
func6 x y=if (x>y) then (func6 y (mod x y)) else (func6 x (mod y x))
--7sushu
func7 =[x|x<-[1..],func77 x]
func77 x=func777 x (x-1)
func777 1 0=False
func777 1 1=False
func777 x 1=True
func777 x y=if( (mod x y) ==0 )then False else (func777 x (y-1))