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