Haskell Lesson:高阶函数

微信公众号:牛顿一号
欢迎关注我,一起学习,一起进步!

前面在实现Graham扫描和Huffman编码的时候其实已经用到了高阶函数的知识。所谓高阶函数就是参数中带有函数,譬如 f2(x) 。通过高阶函数可以进一步对运算过程进行抽象。

一、foldl/foldr/map

这几个函数提供了一种遍历List的方法,可以不用自己去显示的定义递归过程,即所谓的折叠和映射。折叠返回一个累加值,这个累加值不一定是一个数,可以是任何定义的数据类型,相当于从list中提炼出的信息。而map是对list中每个元素做映射,返回的是一个新的list。

1.1 foldl/foldr

foldl表示从左开始折叠,foldl从右开始折叠,map可对一个list进行映射,相关类型如下:

Prelude> 
Prelude> :t foldl
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
Prelude> :t foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
Prelude> :t map
map :: (a -> b) -> [a] -> [b]
Prelude> 

foldl和foldr都接受一个step函数用来处理每一步中对单个元素的处理。

譬如现在要累加一个Int List所有元素的值,可以这样实现。

Prelude> foldl (+) 0 [1,2,3,4]
10

同样的也可以用foldr

Prelude> foldr (+) 0 [1,2,3,4]
10

这里的step函数就是(+)了。

两者的结果是一样的,但是他们在内部进行运算的时候可是截然不同,foldl本质上还是迭代的过程,step函数每次都取累加值和元素进行运算,而foldr取元素和累加值进行运算,它是一个递归的过程,直到遇到list末尾才开始对累加值进行运算。所有能用foldr实现的过程统称为主递归过程(primitive recursive)。

1.2 map

map的类型定义如下:

Prelude> :t map
map :: (a -> b) -> [a] -> [b]

可以看到map对类型并没有限制,给一个a->b的映射函数,就可以把[a]映射成[b]。

譬如要对Int list中的每个元素做平方操作,可以这么写

Prelude> map (^2) [1,2,3,4]
[1,4,9,16]

二、使用范例

foldl和foldr可谓是一大神器,完美的提供了对list的遍历操作,譬如在实现Huffman编码的过程中,我们定义了

getCharCount :: Char -> [Char] -> Int
getCharCount c str = foldl (foo c) 0 str
  where foo = \c1 count c2 ->
                if c1 == c2
                then count+1
                else count

统计一个字符串中某个字符的出现次数,foldl返回次数值。但是在实际中如果每个字符都用这种方法去遍历整个字符串,时间开销将会是 O(n2) ,所以在实际中采用了另外一种更为快速的方法。当时还考虑过痛过foldl直接生成由字符频次构成的Int List,但是从语法上看没有group . sort来的优美。

-- [Int] caintains weight for each character
getAsciiWeight :: [Char] -> [Int]
getAsciiWeight str = [length x| x<-group $ sort str]

先进行排序,然后利用group函数来获取相同的字符序列,该序列的长度即为对应字符出现的频次。

扫一扫关注微信公众号,更多精彩文章等着您
qrcode_for_gh_162a7dca826c_258.jpg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶玄青

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值