如何理解高階函式

bestswifter發表於2018-01-03

昨天開始讀 SICP,這本書作為 MIT 所有理工科類學生的公共必修課(類似於我們們的高數),還是挺有價值的,很清楚的解釋了一些基本概念,這裡先總結一下高階函式吧。

高階函式的定義是接受一個函式作為引數,或者返回一個函式的函式。不過這樣的解釋作為總結也就罷了, 如果用來學習、理解的話。。。。。。還是看具體例子吧。

函式

我們知道函式是對過程的抽象,或者說是對某種過程的通用描述,比如說下面這個求絕對值的過程:

  • 5 -> |5| = 5
  • -1 -> |-1| = 1
  • 0 -> |0| = 0

求絕對值的過程是判斷一個數是否大於等於 0,如果是的話,返回這個數,否則返回它的相反數。於是,為了對這個“複雜”過程進行抽象,我們可以定義一個函式 abs(x), 它專門用來計算一個數的絕對值。

可別小看這個貌似人人都會的簡單的過程,它實際上是一件值得總結的事情,abs(x) 的價值絕不在於它實現求絕對值的過程,而是告訴我們:

如果有一系列操作,僅僅是輸入的引數不同,但是對於引數的處理過程大致相同,我們就可以用函式來抽象這個操作。

求和

我們都熟練的掌握如何計算 1 到 n 中所有自然數的和,自然就可以定義一個函式 sum(a, b),表示從 a 到 b 中所有自然數的和,但如果被求和的不是自然數,而是某個表示式呢?

學過數學的人都知道,有一個符號叫求和符號,也即是這玩意:Σ,上述的 a 和 b 分別是它的上下標,後面還跟著一個函式 f(x)

Σf(x) = f(a) + f(a+1) + …… + f(b)

我們可以看到,Σ 也滿足之前對函式的定義,首先它表示了一些列操作,隨著輸入引數(這時候是一個函式)的不同,它代表了不同的操作。但不管怎樣,它對引數的處理方式總是類似的:依次把 a 到 b 中的每一個數代入到引數函式中,並且求和。

高階函式

很多現代程式語言都實現了陣列的 map 方法,它本質上就是一個高階函式。為什麼這麼說,或者說為什麼要在這裡設計一個高階函式呢?我們可以看一下 map 方法的本質:

for item in array:
item = handle(item)
複製程式碼

你可以看到這個過程的變數其實是 handle 函式,也就是說 map 方法其實是對 “不同的 handle 函式的相似使用” 這一過程的抽象,因此它的引數必須是一個函式,這也就是為什麼 map 是一個高階函式。

同理,reduce 等也是高階函式。

總結

高階函式就是玩函式的,它把函式當做變數來用,回顧一下函式的定義:

如果有一系列操作,僅僅是輸入的引數不同,但是對於引數的處理過程大致相同,我們就可以用函式來抽象這個操作。

這裡並沒有規定引數是什麼,如果是一個數字,那我們可以理解為這是個普通函式;如果變數自身就是一個函式,我們可以理解為這是一個高階函式。

不過我一直堅持的理念是,概念和名詞只是用來簡化、抽象某個具體的描述,它應該被用來方便人們進行交流而不是約束你的思維。所以高階函式就是函式,不用做刻意的區分。

相關文章