高阶函数
文章目录
curried function
我还是直接翻译成“用咖啡煮的函数吧”。 有一个有趣的现象:
Prelude> max 1 2
2
Prelude> (max 1) 2
2
我刚开始觉得这太不可思议了,max 1居然可以执行,而且它的返回值还拿2来当参数! 原来这个函数可以写成下面这两种形式:
Prelude> :t max
max :: Ord a => a -> a -> a
Prelude> :t max
max :: Ord a => a -> (a -> a)
第二种,如果给max传一个参数x,则它返回一个函数,这个函数会接受一个参数y返回和x 比较之后的最大值。 这意味着我们可以传部分参数给一个函数。是不是只有库函数才这样的呢?不是!
-- addThree - adds three numbers, returns their sum
addThree :: (Num a) => a -> a -> a -> a
addThree x y z = x + y + z
运行结果:
*Main> addThree 1 2 3
6
*Main> ((addThree 1) 2) 3
6
这令我非常震惊! 中缀函数也能有这种用法:
{- isUpper - if a character is uppercase, return True,
otherwise, return False.
-}
isUpper :: Char -> Bool
isUpper = (`elem` ['A'..'Z'])
虽然只有一个参数,但是也能看到基本的形式是加一个括号,称为section。
其它的高阶函数
函数可以接受函数作为参数,也可以返回函数。 实现一个标准库函数zipWith,接受一个函数,两个list,根据这个函数的作用返回 2个list合并后的效果。
zip_with :: (a -> b -> c) -> [a] -> [b] -> [c]
zip_with _ [] _ = []
zip_with _ _ [] = []
zip_with func (xFirst:xRest) (yFirst:yRest) =
(func xFirst yFirst) : (zip_with func xRest yRest)
使用一下:
*Main> zip_with (*) [1, 2] [3, 4]
[3,8]
*Main> zip_with max [1, 2] [3, 4]
[3,4]
这就是通用的函数,太厉害了!
一些库函数
map
接受一个函数和一个list作为参数,把这个函数作用于list中的每个函数。
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (first:rest) = f first : map f rest
关键是它的应用,这个函数用起来非常方便。
*Main> map fst [(1, 2), (3, 4)]
[1,3]
*Main> map (* 2) [1, 2, 3]
[2,4,6]
filter
顾名思义,是用来过滤的,接受一个predicate,即判断函数,和一个list,返回一个 满足条件的list。
filter :: (a -> Bool) -> [a] -> [a]
filter _ [] = []
filter predicate (first:rest)
| predicate first = first : filter predicate rest
| otherwise = filter predicate rest
应用:
*Main> filter' (> 3) [1, 2, 3, 4]
[4]
上面这2个函数都可以通过list comprehension来代替。但是使用这样的函数会更容易 理解,可读性更强。
lambdas
其实就是匿名函数(anonymous function)。比如: map (+3) [1, 2, 3] 和 map (\x -> x + 3) [1, 2, 3]是等价的。 使用\来表示匿名函数,上例中,传入参数x,返回值为x + 3。