内容简介:系列文章一个函数满足以下任一条件即为高阶函数《计算的本质》讲得更好一些,我感觉这本书这里讲得不通透。
系列文章
- 《Haskell趣学指南》笔记之基本语法
- 《Haskell趣学指南》笔记之类型(type)
- 《Haskell趣学指南》笔记之函数
- 《Haskell趣学指南》笔记之高阶函数
- 《Haskell趣学指南》笔记之模块
- 《Haskell趣学指南》笔记之自定义类型
一个函数满足以下任一条件即为高阶函数
- 接受函数作为参数
- 将函数作为返回值
《计算的本质》讲得更好一些,我感觉这本书这里讲得不通透。
柯里化
让函数只接受一个参数就够了。 如果想接受两个参数,就先接受一个,返回一个接受另一个参数的函数即可。
multThree :: Int -> Int -> Int -> Int -- 等价于 Int -> (Int -> (Int -> Int)) multThree x y z = x * y * z 复制代码
截断(section)
divideByTen :: (Floating a) => a -> a divideByTen = (/10) -- 这就是截断 isUpperAlphanum :: Char -> Bool isUpperAlphanum = (`elem` ['A'..' Z']) -- 这就是截断 复制代码
一个需要注意的问题是 (-4)
不能表示截断,必须换成 (`subtract` 4)
函数作参数
applyTwice :: (a -> a) -> a -> a -- 注意这里的括号不能省略 applyTwice f x = f (f x) 复制代码
注意这里的括号不能省略,因为 -> 默认是右结合。
技巧:在编写函数(尤其是高阶函数)时如果拿不准函数的类型,可以先不写函数的类型声明,定义完毕后再利用 :t 查看 Haskell 推导出的结果。
工具箱
ghci> map (++ "!") ["BIFF"," BANG"," POW"] ["BIFF!"," BANG!"," POW!"] ghci> filter even [1.. 10] [2, 4, 6, 8, 10] ghci> let listOfFuns = map (*) [0..] ghci> (listOfFuns !! 4) 5 20 复制代码
lambda
lambda 就是一次性的匿名函数。写法是 \param1 param2 -> returnValue
,必要的时候可以用圆括号括起来。
如果参数是二元组,应该怎么声明 lambda:
ghci> map (\(a, b) -> a + b) [(1, 2),( 3, 5)] -- 注意这里的 (a,b) 是模式匹配,不是两个参数 [3, 8] 复制代码
以下例子说明 Haskell 的函数是默认柯里化的
addThree :: Int -> Int -> Int -> Int addThree x y z = x + y + z addThree' :: Int -> Int -> Int -> Int addThree' = \x -> \y -> \z -> x + y + z -- 上面俩函数等价 flip1 :: (a -> b -> c) -> b -> a -> c flip1 f y x = f x y flip2 :: (a -> b -> c) -> b -> a -> c flip2 f = \y x -> f x y -- 上面俩函数等价 复制代码
fold 折叠(类似 reduce)
foldl (\acc x -> acc + x) init list foldr (\x acc -> x : acc) init list foldl1 step list -- 第一个元素就是 init foldr1 step list -- 第一个元素就是 init 复制代码
另一种方式理解折叠:折叠就是对列表中的所有元素连续地应用某个函数。如:
foldr f 0 [1,2,3,4] -- 其实就是 f 1 (f 2 (f 3 (f 4 0))) foldl g 0 [1,2,3,4] -- 其实就是 g (g (g (g 0 1) 2) 3) 4 复制代码
当二元函数 f 不总是需要对第二个参数求值时,即可通过 foldr 对无限列表做处理。fordl 则不行。
scan 与 fold 类似,区别在于 scan 会把每一次 step 的返回值记录在一个列表里。
$ 函数应用符号
后面的是函数的参数,类似 JS 的 .call。
sum $ filter (> 10) $ map (*2) [2.. 10] -- 得到 80 sum (filter (> 10) (map (*2) [2.. 10])) -- 如果不用 $ 就要加很多括号 ghci> map ($ 3) [(4+),( 10*),(^ 2), sqrt] [7. 0, 30. 0, 9. 0, 1. 7320508075688772] 复制代码
函数组合 composition
数学定义: (f·g)(x) = f(g(x))
,它的目的是方便生成新函数。
map (negate . sum . tail) [[1.. 5],[ 3.. 6],[ 1.. 7]] -- [-14,- 15,- 27] 复制代码
如果要组合的函数有多个参数,就只能化为只有一个参数的函数(柯里化)再组合。
sum . replicate 5 $ max 6.7 8.9 --44.5 --等价于 sum . (replicate 5) $ max 6.7 8.9 -- 44.5 复制代码
技巧:如果你打算用组合来省去大量括号,可以先找出最里面的函数和参数,写下来,在前面加一个 前面,如
replicate 2 (product (map (*3) (zipWith max [1, 2] [4, 5]))) -- 改写为 replicate 2 . product . map (*3) $ zipWith max [1, 2] [4, 5] 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Python第六章-函数06-高阶函数
- JS 函数式编程思维简述(二):高阶函数
- Python小世界:匿名函数、高阶函数、推导式
- Python|高阶函数
- Javscript 高阶函数(上)
- 【重温基础】21.高阶函数
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。