高阶函数
此页面的内容最初是为 isaac 计算机科学 编写的 |
高阶函数 是将一个或多个函数作为参数或返回一个函数作为结果的函数。 三个常见的高阶函数是 map、filter 和 reduce/fold 函数
扩展:函子与非列表映射 虽然这里面的例子是关于使用 map、filter 和 reduce/fold 函数处理列表,但其他数据类型可以用来代替列表。例如,你可以将一个函数映射到树的元素上。在 Haskell 中,任何 函子 类型类的东西都可以用于 map 函数中。 |
map
函数被赋予一个列表和一个要应用于该列表的函数。 它将这个给定的函数应用于给定列表中的每个元素,创建一个新的列表,然后返回该列表。 另一种定义 map
的方法是,它将给定列表的每个项映射到输出列表
.> map (+10) [1,2,3,4,5]
[11, 12, 13, 14, 15]
.> map (^2) [20, 3, 51, 6, 3, 7]
[400,9,2601,36,9,49]
.> map (++ "!") ["scary", "weird", "spooky", "kooky"]
["scary!", "weird!", "spooky!", "kooky!"]
.> map ("NOT " ++) ["scary", "weird", "spooky", "kooky"]
["NOT scary", "NOT weird", "NOT spooky", "NOT kooky"]
.> map (replicate 2) ['a', 'b', 'c']
["aa","bb","cc"]
.> map (replicate 2) ["a", "b", "c"]
[["a","a"],["b","b"],["c","c"]]
map 也可以作用于一个列表的列表,其中被映射的函数依次被应用于每个子列表。 例如,如果你想从一组列表中找到最小值,你可以写
.> map minimum [[1, 3], [2, 7, 5],[9, 6]]
[1,2,6]
这里要注意,我们似乎得到一个比开始时更小的列表。 虽然就每个现在只有一个项目的内部列表的长度而言这是真的,但传递给 map 函数的原始列表有三个项目(列表 [1, 3]
、[2, 7, 5]
、[9, 6]
),返回的列表也有三个项目([1,2,6]
)。
filter 函数被传递一个列表和过滤条件,它将过滤条件应用于列表,返回一个匹配过滤条件的项目列表。 过滤条件有时被称为 谓词函数,其中将 TRUE 或 FALSE 返回从将条件应用于原始列表的每个元素。 在 Haskell 中,这是使用 filter
命令执行的,例如
.> let list1 = [1,2,3,4,5,6,7,8,9]
.> filter (>5) list1
这查看 list1
中的每个项目,并检查它们是否大于 5。 将那些大于 5 的设置为True,而那些小于 5 的设置为False
[1,2,3,4,5,6,7,8,9]
[F,F,F,F,F,T,T,T,T]
它返回所有为True 的项目列表
- [6,7,8,9]
使用 odd
和 even
命令的其他 filter 示例
.> let list1 = [1,2,3,4,5,6,7,8,9]
.> let list2 = filter even list1
.> list2
[2, 4, 6, 8]
.> filter odd list1
[1, 3, 5, 7, 9]
.> filter odd list2
[]
其他编程语言可能没有 filter 命令,但可能通过使用 select case
、switch
、if then else
来实现类似的输出。
reduce 或 fold 函数作为输入接受一个列表、一个要应用于列表的函数和一个起始值。 有两种类型的 fold 命令,foldl
和 foldr
,这里面的例子使用的是 foldl
。
fold 将给定的函数应用于列表的第一个元素(从左到右开始)和起始值,然后将 fold 命令应用于此的结果和列表的其余部分。 它递归地执行此操作,直到 fold 命令被应用于一个空列表,此时它返回计算出的值。 另一种描述方式,来自 Haskell wiki
-- [] represents the empty list,
-- and (x:xs) represents the list starting with x and where the rest of the list is xs.
-- if the list is empty, the result is the initial value; else
-- we recurse immediately, making the new initial value the result
-- of combining the old initial value with the first element.
rule 1. foldl f z [] = z
rule 2. foldl f z (x:xs) = foldl f (f z x) xs
为了看到它的实际效果,请查看 haskell 命令 foldl (*) 1 [1,2,3,4]
,此代码将递归地将列表中的元素乘在一起
foldl (*) 1 [1,2,3,4]
这与规则 2. 匹配。 f = *,z = 1,x = 1,xs = [2,3,4]。 由于命令右侧的列表 xs
不是空的,因此我们将执行以下操作
foldl f z (x:xs) = foldl f (f z x) xs
这将进行下一次调用
foldl (*) (* 1 1) [2,3,4]
列表 xs
不是空的,因此我们将再次应用规则 2.,其中 f = *,z = * 1 1,x = 2,xs = [3,4]。 下一次调用是
foldl (*) (* (* 1 1) 2) [3,4]
列表 xs
不是空的,因此我们将再次应用规则 2.,其中 f = *,z = * (* 1 1) 2,x = 3,xs = [4]。 下一次调用是
foldl (*) (* (* (* 1 1) 2) 3) [4]
列表 xs
仍然不是空的,因此我们将再次应用规则 2.,其中 f = *,z = * (* (* 1 1) 2) 3,x = 4,xs = []。 因此,下一次 foldl 调用是
foldl (*) (* (* (* (* 1 1) 2) 3) 4) []
列表 xs
现在是空列表 []
。 这与规则 1. 匹配,并返回 z
(* (* (* (* 1 1) 2) 3) 4)
我们可以将 波兰表示法(例如 * 1 1
)改写为 中缀表示法(例如 1 * 1
),并计算出括号,从最里面的括号开始
((((1*1)*2)*3)*4)
(((1*2)*3)*4)
((2*3)*4)
(6*4)
24
使用中缀表示法的更简洁的加总示例
foldl (+) 0 [1,2,3,4]
foldl (+) (0+1) [2,3,4]
foldl (+) ((0+1)+2) [3,4]
foldl (+) (((0+1)+2)+3) [4]
foldl (+) ((((0+1)+2)+3)+4) []
((((0+1)+2)+3)+4)
((((1)+2)+3)+4)
(((3)+3)+4)
((6)+4)
10
考试问题 什么是高阶函数? 答案 一个函数,它将函数作为参数或返回一个函数作为结果,或者两者都做
Haskell 命令 答案
Haskell 命令 答案
Haskell 命令 答案
Haskell 命令 答案
答案
答案
答案
答案
写下执行 答案 foldl (^) 2 [3, 2, 1]
foldl (^) (2^3) [2, 1]
foldl (^) ((2^3)^2) [1]
foldl (^) (((2^3)^2)^1) []
(((2^3)^2)^1)
(((8)^2)^1)
((64)^1)
64
描述一等公民和高阶函数之间的区别 答案 一等公民是一个可以作为参数传递或由函数返回的对象。 高阶函数可以接受另一个函数作为参数。
|