高階函式
| 此頁面的材料最初是為 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
描述一等物件和高階函式之間的區別 回答 一等物件是可以作為引數傳遞或由函式返回的物件。高階函式可以接受另一個函式作為引數。
|