Higher-Order Functions

背景

說好的看Learn You a Haskell for Great Good,寒假敲了很多,到higher-order function卡了。光敲已經不能理解了。最近的早上有時候去的早就會看一看理解一下Haskell,把higher-order function看了小半,Lambdas以前的部分,準備寫一寫,也算是個記錄。不得不感嘆,這玩意真TM難懂。編程

introduction

首先簡單的說一下Haskell的語法,只有這樣我才能更好的把後面的東西寫明白。swift

首先來看一個函數,lucky。app

lucky :: Int -> String
lucky 7 = "LUCKY NUMBER SEVEN!"
lucky x = "Sorry, you're out of luck, pal!"

這個其實和swift的語法很類似,以致於我以爲swift這裏很大程度上借鑑了haskell的語法。lucky做爲一個函數,參數是一個Int類型,返回值是一個String類型。當咱們運行時,若是是7,就會顯示是幸運數字,若是不是,那就顯示sorry。函數式編程

higher-order function

什麼是higher-order function。在haskell第五章的開始說了。函數

Haskell functions can take functions as parameters and return functions as return values. A function that does either of these things is called a higher-order function.學習

在wiki中得介紹是這樣的。code

在數學和計算機科學中,高階函數是至少知足下列一個條件的函數:
接受一個或多個函數做爲輸入
輸出一個函數對象

能夠看到這兩個其實想表達的意思是同樣的。那就是,函數做爲參數,或者返回一個函數。blog

簡單的說,在C語言中,咱們都是這麼寫的...void func(int, int) return void。ip

在haskell中,咱們能夠這麼寫,func func(func, func) return func。

在函數式編程中,函數已經成爲了頭等公民。這就是高階函數。到這基本上就能夠理解面向對象老是說函數式把函數傳來傳去的梗了...

func return func

咱們一個一個來看。先看返回一個函數的狀況。

multThree :: Int -> Int -> Int -> Int
multThree x y z = x * y * z

這是一個函數,參數是三個Int類型,返回這三個Int的乘積。

也能夠寫成這樣。

multThree :: Int -> (Int -> (Int -> Int))

因此,咱們來分析書上的一個例子。

ghci> let multTwoWithNine = multThree 9
ghci> multTwoWithNine 2 3
54

在這裏,咱們讓multTwoWithNine等於了一個函數,這個函數是multThree 9。那這個時候multThree 9實際上算是返回了一個函數。那麼這樣的話,能夠將這個函數賦值爲一個變量。

也就是咱們的multTwoWithNine。這個時候咱們的multTwoWithNine實際上要計算的就是兩個數的乘積再乘上9,而乘9,實際上不算是一個函數。

這裏就達到了函數返回一個函數。即個人標題,func return func。

func as parameters

來看例子。

In Haskell, functions can take other functions as parameters, and as you’ve seen, they can also return functions as return values.

也就是說,函數能夠將函數做爲參數。

applyTwice :: (a -> a) -> a -> a
 applyTwice f x = f (f x)

這個例子種,f實際上就是一個方法。

看個例子就明白了。

ghci> applyTwice (+3) 10
16

在這裏,咱們看上去applyTwice有三個參數,可是前兩個參數被包起來了。也就是說,咱們有一個函數參數,一個參數和一個返回值。

f x = f (f x)實際上就是f方法執行了兩次。

怎麼去理解高階函數呢?實際上在我看來,能夠這麼理解,第一個函數參數,實際上實現了在第三個參數的操做。

爲何這裏會等於16,實際上這樣操做的。10 + 3 + 3。也就是,實際上第三個參數執行了函數參數的方法,獲得了返回值。

說了這麼多仍是混亂是吧...感受上這個例子可能不能很好的說明。那咱們看兩個好懂的。

zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' _ [] _ = []
zipWith' _ _ [] = []
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys

按照我上面說的,第一個函數參數,其實是a,b參數返回c。

那麼咱們對[a]中的元素和[b]中的元素執行第一個函數的方法,最後返回的應該是列表中的每個元素操做後的結果。

ghci> zipWith' (+) [4,2,5,6] [2,6,2,3]
[6,8,7,9]

這個例子中,對[a]和[b]中的每個元素進行+操做。實際上就是第一個(a -> b -> c)中的操做了。

第二行和第三行的意思實際上是,第一個函數參數無論它什麼類型,咱們迪哥參數和第三個參數只要是列表,就返回列表。

這麼一看,其實高階函數也不是很難吧。

再看一個map,這個在rac和rx都有用到。

map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs

咱們看這個函數,按照對zipWith'的理解,咱們知道,這個操做實際上是對[a]列表中的元素進行操做,而後這些值返回一個[b]列表。

咱們來分析一個複雜點的map。

ghci> map (map (^2)) [[1,2],[3,4,5,6],[7,8]]

首先咱們(a -> b)要進行的函數操做實際上是(map (^2)),那對第一個列表[1,2]來講,又是一個列表了,因此要返回一個列表。(map (^2)) 1 的結果是1,(map (^2)) 2的結果是4,而後返回一個列表,即[1,4]。一次類推,因此結果就是。

[[1,4],[9,16,25,36],[49,64]]

swift中的應用

Swift 燒腦體操(三) - 高階函數看到了swift中高階函數的運用。

那咱們來遷移一下理解。

let arr = [1, 2, 4]
// arr = [1, 2, 4]

let brr = arr.map {
    "No." + String($0)
}
// brr = ["No.1", "No.2", "No.4"]

第一個arr.map,在map中,實際上就是實現了咱們上文map中f的應用,對列表裏的每一個元素就會進行操做。實際上和haskell中的map函數沒有什麼差異了。

實際上來講,高階函數的應用不少,後面我在學習swift以後會繼續說說這個高階函數,固然,在我能搞定的狀況下,我想嘗試去學學Monad。

相關文章
相關標籤/搜索