40
高高高高 Higher Order Functions 高高高高高 高高高

高阶函数 Higher Order Functions

  • Upload
    tuan

  • View
    144

  • Download
    0

Embed Size (px)

DESCRIPTION

高阶函数 Higher Order Functions. 阅读第九章、第十章. 计算模式的推广. 我们经常需要对列表的元素进行某种统一的操作 : doubleAll :: [Int] -> [Int] doubleAll [] = [] doubleAll (x:xs) = 2*x : doubleAll xs 或者 doubleAll xs = [2*x | x Bool even n = n`mod` 2 == 0. 又如 : is Even xs = [even x | x

Citation preview

Page 1: 高阶函数 Higher Order Functions

高阶函数Higher Order Functions

阅读第九章、第十章

Page 2: 高阶函数 Higher Order Functions

计算模式的推广

我们经常需要对列表的元素进行某种统一的操作: doubleAll :: [Int] -> [Int]

doubleAll [] = []

doubleAll (x:xs) = 2*x : doubleAll xs

或者 doubleAll xs = [2*x | x<- xs]

又如:

isEven xs = [even x | x <- xs]

even :: Int -> Booleven n = n`mod` 2 == 0

Page 3: 高阶函数 Higher Order Functions

高阶函数

一般的计算模式: [x, y, z, …] [ f x, f y, f z, …]

我们把这种模式称作映射 map :

map f xs = [f x | x <- xs]

map 的第一个参数是函数,这种以函数为输入 的函数称为高阶函数 (higher order functions) 。

map 的另一种定义方法map f [] = [] .

map f (x:xs) = f x : map f xs

Page 4: 高阶函数 Higher Order Functions

例如

map double [1,2,3,4,5] = [2,4,6,8,10]

map even [1, 2, 3, 4, 5] = [False, True, False, True, False]

使用高阶函数可以书写更简洁的函数定义:

doubleAll xs = map double xs

isEven xs = map even xs

Page 5: 高阶函数 Higher Order Functions

map 的类型是什么?map even [1, 2, 3, 4, 5] = [False, True, False, True, False]

任意一元函数 任何 a 上的列表

结果是 b 上的列表map 的类型是多态的map :: (a -> b) -> [a] -> [b]

map double [1,2,3,4,5] = [2,4,6,8,10]

map :: (Int -> Bool) -> [Int] -> [Bool]

map :: (Int -> Int) -> [Int] -> [Int]

Page 6: 高阶函数 Higher Order Functions

使用 map 定义水平翻转

flipH

[” # ”, ” # ”, ”######”, ” # ”, ” # ”]

[” # ”, ” # ”, ”######”, ” # ”, ” # ”]

flipH :: Picture -> Picture

flipH pic = [reverse line | line <- pic]

filpH pic = map reverse pic

Page 7: 高阶函数 Higher Order Functions

过滤函数

例如,选出列表中的偶数: [x | x<- [1..5], even x] = [2,4]

又如,选取一个串中的数字 [x | x <- “born on 15 April 1986”, isDigit x] = “151

986”

一般地,我们定义如下过滤模式

filter p xs = [x | x <- xs, p x]

isDigit :: Char -> Bool

Page 8: 高阶函数 Higher Order Functions

Filter 的类型是什么 ?

filter even [1, 2, 3, 4, 5] = [2, 4]

even :: Int -> Bool

filter :: (Int -> Bool) -> [Int] -> [Int]

filter :: (a -> Bool) -> [a] -> [a]

一个表示性质的函数类型

Page 9: 高阶函数 Higher Order Functions

为什么使用高阶函数?

• 高阶函数是函数程序设计的灵魂。• 许多相似的函数都可以使用一个高阶函数代替。• 高阶函数比一阶函数更具有表现力,我们可以通过使用不同的函数参数解决不同的问题。• 每当多个函数具有相似的模式时,定义一个高阶函数。

Page 10: 高阶函数 Higher Order Functions

折叠的例子

sum [] = 0sum (x:xs) = x + sum xs

计算模式:使用同一个运算将列表的元素结合起来。

具体到 sum: 起始值 0, 运算 +

and: 起始值 True, 运算 &&

and [] = True and (x:xs) = x && (and xs)

sum [2,4,6] = 12 and [True, False, True] = False

Page 11: 高阶函数 Higher Order Functions

折叠函数

sum [] = 0sum (x:xs) = x + sum xs

将 0 和 + 分别用参数代替 , 定义一个高阶函数 :

foldr op z [] = zfoldr op z (x:xs) = x `op` foldr op z xs

sum xs = foldr plus 0 xs

where plus x y = x+y

Page 12: 高阶函数 Higher Order Functions

sum xs = foldr plus 0 xs

where plus x y = x+y

sum xs = foldr (+) 0 xs

使用 foldr 定义的 sum

或者

Page 13: 高阶函数 Higher Order Functions

使用 foldr 的函数定义

将列表元素使用某种运算结合起来是一种常见运算,这种运算均可以使用 foldr 定义,而不必使用递归。

product xs = foldr (*) 1 xsconcat xs = foldr (++) [] xsmaximum (x:xs) = foldr max x xs

Page 14: 高阶函数 Higher Order Functions

函数 foldr 的另一种解读

foldr op z [] = zfoldr op z (x:xs) = x `op` foldr op z xs

例如foldr op z (a:(b:(c:[]))) = a `op` foldr op z (b:(c:[]))

= a `op` (b `op` foldr op z (c:[]))

= a `op` (b `op` (c `op` foldr op z []))

= a `op` (b `op` (c `op` z))

运算 “ :” 被 `op` 代替 , [] 被 z 代替 .

Page 15: 高阶函数 Higher Order Functions

问题

解释下列表达式的语义foldr (:) [] xs

foldr (:) [] xs = xs

Page 16: 高阶函数 Higher Order Functions

问题

解释foldr (:) ys xs

foldr (:) ys [a,b,c]

= foldr (:) ys (a:(b:(c:[])))

= (a:(b: (c: ys))

= [a,b,c] ++ ys xs++ys = foldr (:) ys xs

Page 17: 高阶函数 Higher Order Functions

问题

解释 foldr snoc [] xs

where snoc y ys = ys++[y]

foldr snoc [] (a:(b:(c:[])))

= a `snoc` (b `snoc` (c `snoc` []))

= (([] ++ [c]) ++ [b] ++ [a]

结果是 xs的逆 !reverse xs = foldr snoc [] xs where snoc y ys = ys++[y]

Page 18: 高阶函数 Higher Order Functions

表达式

表达式是函数的一种表示方法。例如 double x = 2*x

函数 double 可以表示为 double = x. 2*x

在 Haskell 中表示为 double = \x -> 2*x

当输入参数是 x 时,函数的结果是 2*x

Page 19: 高阶函数 Higher Order Functions

例 max x y = if (x<y) then y else x使用 lambda 表达式 max = \x\y -> if (x<y) then y else x 或者 max = \x y -> if (x<y) then y lese x

一般地,下列定义等价:

f x y z = e

f = \x y z -> e

Page 20: 高阶函数 Higher Order Functions

使用表达式定义函数

reverse xs = foldr snoc [] xs where snoc y ys = ys++[y]

可以直接使用 lambda表达式代替只出现一次的函数

reverse xs = foldr (\y ys -> ys++[y]) [] xs

Page 21: 高阶函数 Higher Order Functions

定义函数 unlines

unlines [“abc”, “def”, “ghi”] = “abc\ndef\nghi\n”

unlines [xs,ys,zs] = xs ++ “\n” ++ (ys ++ “\n” ++ (zs ++ “\n” ++ []))

unlines xss = foldr (xs ys -> xs++“\n”++ys) [] xss

等价于

unlines xss = foldr join [] xss

where join xs ys = xs ++ “\n” ++ ys

Page 22: 高阶函数 Higher Order Functions

又一个计算模式

在一个串中取出一个单词:takeWord “Hello, world!” = “Hello”

takeWord [] = []takeWord (x:xs) | x/=‘ ‘ && x/=‘,’ = x:takeWord xs

| otherwise = []

模式:

当某个条件不成立时取得列表元素,直至条件为True 。

Page 23: 高阶函数 Higher Order Functions

推广 takeWord

takeWhile p [] = []takeWhile p (x:xs) | p x = x:takeWhile p xs

| otherwise = []

新定义 takeWord xs = takeWhile (x -> elem x “ ,.;”) xs

takeWord [] = []takeWord (x:xs) | notSpace x = x:takeWord xs

| otherwise = [] where notSpace x = elem x “ ,;.”

Page 24: 高阶函数 Higher Order Functions

函数的表示法 : Sections

一个二元运算只带有一个参数时表示一个函数,称为部分运算( sections):

(+1) :: Int -> Int

(1+) :: Int -> Int

•map (+1) [1,2,3] = [2,3,4]

•filter (<0) [1,-2,3] = [-2]

•takeWhile (0<) [1,-2,3] = [1,3]

(a¤) b = a¤b(¤a) b = b¤a

Page 25: 高阶函数 Higher Order Functions

部分应用

Haskell 允许如下定义sum = foldr (+) 0

foldr 只带有三个参数中的两个。

sum xs = foldr (+) 0 xs

Page 26: 高阶函数 Higher Order Functions

sum = foldr (+) 0

计算 sum [1,2,3]

= {replacing sum by its definition}

foldr (+) 0 [1,2,3]

= {by the behaviour of foldr}

1 + (2 + (3 + 0))

= 6

foldr 有三个参数

Page 27: 高阶函数 Higher Order Functions

部分应用

任何函数都可以应用于部分输入参数,结果是剩余参数的函数:

如果

f ::Int -> Bool -> Int -> Bool

则 f 3 :: Bool -> Int -> Bool

f 3 True :: Int -> Bool

f 3 True 4 :: Bool

一个函数得到一个输入后成为等待其

他输入的函数

Page 28: 高阶函数 Higher Order Functions

函数应用和类型的括号结合方法

函数应用是左结合的,函数类型是右结合的:例如 f ::Int -> (Bool -> (Int -> Bool))

或者 f :: Int -> Bool -> Int -> Bool

则 f 3 :: Bool -> (Int -> Bool)

(f 3) True :: Int -> Bool

((f 3) True) 4 :: Bool

Page 29: 高阶函数 Higher Order Functions

使用高阶函数

• 将问题分解成一系列能够使用高阶函数编程的步骤;• 逐渐将输入转换为期望的输出;• 将这些转换函数组合起来。

Page 30: 高阶函数 Higher Order Functions

例:计算词数输入:

一个由许多词构成、表示文本的串。

例如“hello clouds \n hello sky”

输出:

一个文本中出现的所有词及其出现次数的列表,单词按照字典序排列。如

“clouds: 1\nhello: 2\nsky: 1”clouds: 1hello: 2sky: 1

Page 31: 高阶函数 Higher Order Functions

第一步:将输入分解成词的列表

“hello clouds \n hello sky”

[“hello”, “clouds”, “hello”, “sky”]

words

Page 32: 高阶函数 Higher Order Functions

第二步:排序

[“clouds”, “hello”, “hello”, “sky”]

sort

[“hello”, “clouds”, “hello”, “sky”]

Page 33: 高阶函数 Higher Order Functions

第三步:将相同的词并入一组

[[“clouds”], [“hello”, “hello”], [“sky”]]

group

[“clouds”, “hello”, “hello”, “sky”]

Page 34: 高阶函数 Higher Order Functions

第四步:计算每组词数

[(“clouds”,1), (“hello”, 2), (“sky”,1)]

map (ws -> (head ws, length ws))

[[“clouds”], [“hello”, “hello”], [“sky”]]

Page 35: 高阶函数 Higher Order Functions

第五步:格式化每一组

[“clouds: 1”, “hello: 2”, “sky: 1”]

map ((w,n) -> w++show n)

[(“clouds”,1), (“hello”, 2), (“sky”,1)]

Page 36: 高阶函数 Higher Order Functions

第六步:将列表格式化

“clouds: 1\nhello: 2\nsky: 1\n”

unlines

[“clouds: 1”, “hello: 2”, “sky: 1”]

clouds: 1hello: 2sky: 1

Page 37: 高阶函数 Higher Order Functions

完整的程序

countWords :: String -> String

countWords =

unlines .

map ((w,n) -> w++show n) .

map (ws -> (head ws, length ws)) .

groupBy (==) .

sort .

words

Page 38: 高阶函数 Higher Order Functions

函数 groupBy

group = groupBy (==)

groupBy :: (a -> a -> Bool) -> [a] -> [[a]]

groupBy p xs -- 将 xs 分解成 段的列表 [x1,x2…], 其中每一段上的所有元素均满足某个性质

Page 39: 高阶函数 Higher Order Functions

小结

• 高阶函数是计算模式的抽象。高阶函数的参数是函数。• 高阶函数使得许多函数的更简洁、灵活,而且大大减少了编程工作量。• 表达式、部分运算和部分应用可用于表示函数,作为参数时无需另行定义。• Haskell提供了许多高阶函数。• 解决问题的一般步骤:将问题分解成能够用现有函数解决的问题,然后将这些函数粘合起来。

Page 40: 高阶函数 Higher Order Functions

• 习题: 9.9, 9.10, 9.14, 9.16, 10.4, 10.7, 10.9