高阶函数 #
一、高阶函数基础 #
1.1 什么是高阶函数 #
高阶函数是接受函数作为参数或返回函数的函数:
haskell
-- 接受函数参数
map :: (a -> b) -> [a] -> [b]
-- 返回函数
compose :: (b -> c) -> (a -> b) -> (a -> c)
1.2 函数作为一等公民 #
haskell
-- 函数可以赋值给变量
addOne = (+1)
-- 函数可以作为参数
applyTwice :: (a -> a) -> a -> a
applyTwice f x = f (f x)
-- 函数可以作为返回值
makeMultiplier :: Int -> (Int -> Int)
makeMultiplier n = (*n)
二、map函数 #
2.1 基本用法 #
haskell
-- 类型签名
map :: (a -> b) -> [a] -> [b]
-- 示例
map (*2) [1, 2, 3, 4, 5] -- [2, 4, 6, 8, 10]
map (+1) [1, 2, 3] -- [2, 3, 4]
map show [1, 2, 3] -- ["1", "2", "3"]
map length ["hello", "world"] -- [5, 5]
2.2 实现原理 #
haskell
-- map实现
map' :: (a -> b) -> [a] -> [b]
map' _ [] = []
map' f (x:xs) = f x : map' f xs
2.3 复杂映射 #
haskell
-- 映射复杂类型
map fst [(1, 'a'), (2, 'b'), (3, 'c')] -- [1, 2, 3]
-- 链式映射
map (*2) (map (+1) [1, 2, 3]) -- [4, 6, 8]
-- 使用组合
map ((*2) . (+1)) [1, 2, 3] -- [4, 6, 8]
三、filter函数 #
3.1 基本用法 #
haskell
-- 类型签名
filter :: (a -> Bool) -> [a] -> [a]
-- 示例
filter even [1..10] -- [2, 4, 6, 8, 10]
filter (>5) [1..10] -- [6, 7, 8, 9, 10]
filter (`elem` "aeiou") "hello world" -- "eoo"
3.2 实现原理 #
haskell
-- filter实现
filter' :: (a -> Bool) -> [a] -> [a]
filter' _ [] = []
filter' p (x:xs)
| p x = x : filter' p xs
| otherwise = filter' p xs
3.3 复杂过滤 #
haskell
-- 多条件过滤
filter (\x -> x > 3 && x < 8) [1..10] -- [4, 5, 6, 7]
-- 过滤Maybe值
catMaybes :: [Maybe a] -> [a]
catMaybes = map fromJust . filter isJust
where
fromJust (Just x) = x
isJust (Just _) = True
isJust Nothing = False
-- 过滤元组
filter (\(x, y) -> x > y) [(1, 2), (3, 1), (5, 5), (6, 2)]
-- [(3, 1), (6, 2)]
四、fold函数 #
4.1 foldr - 右折叠 #
haskell
-- 类型签名
foldr :: (a -> b -> b) -> b -> [a] -> b
-- 示例
foldr (+) 0 [1, 2, 3, 4, 5] -- 15
foldr (*) 1 [1, 2, 3, 4] -- 24
foldr (:) [] [1, 2, 3] -- [1, 2, 3]
-- 计算过程
-- foldr (+) 0 [1, 2, 3]
-- = 1 + (2 + (3 + 0))
-- = 1 + (2 + 3)
-- = 1 + 5
-- = 6
4.2 foldl - 左折叠 #
haskell
-- 类型签名
foldl :: (b -> a -> b) -> b -> [a] -> b
-- 示例
foldl (+) 0 [1, 2, 3, 4, 5] -- 15
foldl (*) 1 [1, 2, 3, 4] -- 24
foldl (flip (:)) [] [1, 2, 3] -- [3, 2, 1]
-- 计算过程
-- foldl (+) 0 [1, 2, 3]
-- = ((0 + 1) + 2) + 3
-- = (1 + 2) + 3
-- = 3 + 3
-- = 6
4.3 fold实现 #
haskell
-- foldr实现
foldr' :: (a -> b -> b) -> b -> [a] -> b
foldr' _ z [] = z
foldr' f z (x:xs) = f x (foldr' f z xs)
-- foldl实现
foldl' :: (b -> a -> b) -> b -> [a] -> b
foldl' _ z [] = z
foldl' f z (x:xs) = foldl' f (f z x) xs
4.4 fold应用 #
haskell
-- 求和
sum' :: Num a => [a] -> a
sum' = foldl (+) 0
-- 求积
product' :: Num a => [a] -> a
product' = foldl (*) 1
-- 长度
length' :: [a] -> Int
length' = foldl (\acc _ -> acc + 1) 0
-- 反转
reverse' :: [a] -> [a]
reverse' = foldl (flip (:)) []
-- 拼接
concat' :: [[a]] -> [a]
concat' = foldr (++) []
五、zipWith函数 #
5.1 基本用法 #
haskell
-- 类型签名
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
-- 示例
zipWith (+) [1, 2, 3] [4, 5, 6] -- [5, 7, 9]
zipWith (*) [1, 2, 3] [4, 5, 6] -- [4, 10, 18]
zipWith (,) [1, 2, 3] ['a', 'b', 'c'] -- [(1, 'a'), (2, 'b'), (3, 'c')]
5.2 实现原理 #
haskell
-- zipWith实现
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' _ [] _ = []
zipWith' _ _ [] = []
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys
5.3 复杂应用 #
haskell
-- 点积
dotProduct :: [Int] -> [Int] -> Int
dotProduct xs ys = sum (zipWith (*) xs ys)
-- 元素级操作
elementWiseMax :: [Int] -> [Int] -> [Int]
elementWiseMax = zipWith max
-- 列表相减
listSubtract :: [Int] -> [Int] -> [Int]
listSubtract = zipWith (-)
六、其他常用高阶函数 #
6.1 takeWhile和dropWhile #
haskell
-- takeWhile:取满足条件的元素直到第一个不满足
takeWhile :: (a -> Bool) -> [a] -> [a]
takeWhile _ [] = []
takeWhile p (x:xs)
| p x = x : takeWhile p xs
| otherwise = []
-- 示例
takeWhile (< 5) [1..10] -- [1, 2, 3, 4]
takeWhile even [2, 4, 6, 7, 8] -- [2, 4, 6]
-- dropWhile:丢弃满足条件的元素直到第一个不满足
dropWhile :: (a -> Bool) -> [a] -> [a]
dropWhile _ [] = []
dropWhile p (x:xs)
| p x = dropWhile p xs
| otherwise = x:xs
-- 示例
dropWhile (< 5) [1..10] -- [5, 6, 7, 8, 9, 10]
6.2 span和break #
haskell
-- span:分割为满足和不满足两部分
span :: (a -> Bool) -> [a] -> ([a], [a])
span p xs = (takeWhile p xs, dropWhile p xs)
-- 示例
span (< 5) [1..10] -- ([1, 2, 3, 4], [5, 6, 7, 8, 9, 10])
-- break:span的否定版本
break :: (a -> Bool) -> [a] -> ([a], [a])
break p = span (not . p)
-- 示例
break (> 5) [1..10] -- ([1, 2, 3, 4, 5], [6, 7, 8, 9, 10])
6.3 partition #
haskell
-- partition:按条件分为两部分
partition :: (a -> Bool) -> [a] -> ([a], [a])
partition p xs = (filter p xs, filter (not . p) xs)
-- 示例
partition even [1..10] -- ([2, 4, 6, 8, 10], [1, 3, 5, 7, 9])
6.4 scan #
haskell
-- scanl:类似foldl但保留中间结果
scanl :: (b -> a -> b) -> b -> [a] -> [b]
scanl f z xs = z : case xs of
[] -> []
x:xs -> scanl f (f z x) xs
-- 示例
scanl (+) 0 [1, 2, 3, 4] -- [0, 1, 3, 6, 10]
scanl (*) 1 [1, 2, 3, 4] -- [1, 1, 2, 6, 24]
-- scanr:类似foldr但保留中间结果
scanr :: (a -> b -> b) -> b -> [a] -> [b]
scanr _ z [] = [z]
scanr f z (x:xs) = f x (head ys) : ys
where ys = scanr f z xs
-- 示例
scanr (+) 0 [1, 2, 3, 4] -- [10, 9, 7, 4, 0]
七、函数组合 #
7.1 组合运算符 #
haskell
-- 组合运算符
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(f . g) x = f (g x)
-- 示例
doubleAndAddOne = (+1) . (*2)
doubleAndAddOne 5 -- 11
-- 多函数组合
pipeline = show . (*2) . (+1)
pipeline 5 -- "12"
7.2 无点风格 #
haskell
-- 有参数形式
sumOfSquares xs = sum (map (^2) xs)
-- 无点形式
sumOfSquares' = sum . map (^2)
-- 另一个例子
-- 有参数
evenLength xs = even (length xs)
-- 无点
evenLength' = even . length
7.3 组合链 #
haskell
-- 长组合链
process :: [Int] -> String
process = show . sum . filter even . map (*2)
-- 等价于
process' xs = show (sum (filter even (map (*2) xs)))
-- 使用
process [1..10] -- "60"
八、实践示例 #
8.1 数据处理管道 #
haskell
-- 处理学生成绩
type Student = (String, Int, Int) -- (姓名, 数学, 英语)
-- 获取平均分高于80的学生姓名
topStudents :: [Student] -> [String]
topStudents = map getName . filter isTop
where
getName (name, _, _) = name
isTop (_, math, eng) = (math + eng) `div` 2 > 80
-- 计算总分
totalScores :: [Student] -> [(String, Int)]
totalScores = map (\(name, m, e) -> (name, m + e))
8.2 字符串处理 #
haskell
import Data.Char
-- 统计单词
wordCount :: String -> Int
wordCount = length . words
-- 统计字母
letterCount :: String -> Int
letterCount = length . filter isLetter
-- 大写所有单词
capitalizeWords :: String -> String
capitalizeWords = unwords . map capitalize . words
where
capitalize (x:xs) = toUpper x : xs
capitalize [] = []
8.3 数学计算 #
haskell
-- 阶乘
factorial :: Integer -> Integer
factorial n = product [1..n]
-- 组合数 C(n, k)
combinations :: Integer -> Integer -> Integer
combinations n k = factorial n `div` (factorial k * factorial (n - k))
-- 斐波那契数列
fibs :: [Integer]
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
-- 获取第n个斐波那契数
fib :: Int -> Integer
fib n = fibs !! n
8.4 列表操作 #
haskell
-- 去重
nub :: Eq a => [a] -> [a]
nub = foldr (\x xs -> x : filter (/= x) xs) []
-- 排序并去重
uniqueSort :: Ord a => [a] -> [a]
uniqueSort = nub . sort
-- 分组
group :: Eq a => [a] -> [[a]]
group = foldr f []
where
f x [] = [[x]]
f x (ys:yss)
| x == head ys = (x:ys):yss
| otherwise = [x]:ys:yss
九、性能考虑 #
9.1 foldl vs foldr #
haskell
-- foldl可能产生空间泄漏
-- 使用严格的foldl'
import Data.List (foldl')
-- 严格版本
sumStrict :: [Int] -> Int
sumStrict = foldl' (+) 0
-- foldr可以处理无限列表
-- foldl不能
take 5 (foldr (:) [] [1..]) -- [1, 2, 3, 4, 5]
-- take 5 (foldl (flip (:)) [] [1..]) -- 无限循环
9.2 组合优化 #
haskell
-- 多次遍历
process1 xs = sum (filter even (map (*2) xs))
-- 单次遍历(使用fold)
process2 xs = foldl' (\acc x -> if even (x*2) then acc + x*2 else acc) 0 xs
十、总结 #
高阶函数要点:
- map:对列表每个元素应用函数
- filter:过滤满足条件的元素
- fold:将列表归约为单个值
- zipWith:两个列表元素配对操作
- takeWhile/dropWhile:条件取/弃元素
- scan:类似fold但保留中间结果
- 函数组合:使用
.连接函数 - 无点风格:省略参数的简洁写法
掌握高阶函数后,让我们继续学习函数组合。
最后更新:2026-03-27