Python函數語言程式設計:從入門到走火入魔

雨神姥爺發表於2016-12-04

很多人都在談論函數語言程式設計(Functional Programming),只是很多人站在不同的角度看到的是完全不一樣的風景。堅持實用主義的 Python 老司機們對待 FP 的態度應該更加包容,雖然他們不相信銀彈,但冥冥中似乎能感覺到 FP 暗合了 Python 教義(The Zen of Python)的某些思想,而且既然 Python 是一門多正規化程式語言,並在很大程度上支援函數語言程式設計,那就更沒有理由拒絕它。

函數語言程式設計源自於數學理論,它似乎也更適用於數學計算相關的場景,因此本文以一個簡單的資料處理問題為例,逐步介紹 Python 函數語言程式設計從入門到走火入魔的過程。

問題:計算 N 位同學在某份試卷的 M 道選擇題上的得分(每道題目的分值不同)。

首先來生成一組用於計算的偽造資料:

入門

首先來看常規的程式導向程式設計風格,我們需要遍歷每個學生,然後遍歷每個學生對每道題目的答案並與真實答案進行比較,然後將正確答案的分數累計:

如果你覺得上面的程式碼非常直觀且合乎邏輯,那說明你已經習慣按照計算機的思維模式進行思考了。通過建立巢狀兩個 for 迴圈來遍歷所有題目答案的判斷和評分,這完全是為計算機服務的思路,雖然說 Python 中的 for 迴圈已經比 C 語言更進了一步,通常不需要額外的狀態變數來記錄當前迴圈的次數,但有時候也不得不使用狀態變數,如上例中第二個迴圈中比較兩個列表的元素。函數語言程式設計的一大特點就是儘量拋棄這種明顯迴圈遍歷的做法,而是把注意集中在解決問題本身,一如在現實中我們批改試卷時,只需要將兩組答案並列進行比較即可:

然後再將所有正確題目的分數累加起來,即可:

以上是對一位學生的結果處理,接下來只需要對所有學生進行同樣的處理即可:

上面的示例通過 zip/filter/reduce/map 等函式將資料處理的方法打包應用到資料上,實現了基本的函數語言程式設計操作。但是如果你對函式式有更深入的瞭解,你就會發現上面的 cal 方法中使用了全域性變數 QUIZE,這會導致在相同輸入的條件下,函式可能產生不同的輸出,這是 FP 的大忌,因此需要進行整改:

如此藉助閉包(Closure)的方法,就可以維持純淨的 FP 模式啦!

走火(fn.py)

也許看了上面的 FP 寫法,你還是覺得挺囉嗦的,並沒有達到你想象中的結果,這時候就需要呈上一款語法糖利器:fn.pyfn.py 封裝了一些常用的 FP 函式及語法糖,可以大大簡化你的程式碼!

首先從剛剛的閉包開始,我們可以用更加 FP 的方法來解決這一問題,稱為柯里化,簡單來說就是允許接受多個引數的函式可以分次執行,每次只接受一個引數

應用到上面的 cal 方法中:

在 FP 中資料通常被看作是一段資料流在一串函式的管道中傳遞,因此上面的reducefilter其實可以合併:

雖然更簡略了,但是這樣會大大降低程式碼的可讀性(這也是 FP 容易遭受批評的一點),為此 fn 提供了更高階的函式操作工具:

入魔(Hy)

如果你覺得上面的程式碼已經足夠魔性到看起來不像是 Python 語言了,然而一旦接受了這樣的語法設定感覺也還挺不錯的。如果你興沖沖地拿去給 Lisp 或 Haskell 程式設計師看,則一定會被無情地鄙視?,於是你痛定思痛下定決心繼續挖掘 Python 函數語言程式設計的奧妙,那麼恭喜你,組織歡迎你的加入:Hail Hydrahydra

哦不對,說漏了,是Hi Hyhy-logo

Hy 是基於 Python 的 Lisp 方言,可以與 Python 程式碼進行完美互嵌(如果你更偏好 PyPy,同樣也有類似的Pixie),除此之外你也可以把它當做一門獨立的語言來看待,它有自己的直譯器,可以當做獨立的指令碼語言來使用:

首先來看一下它的基本用法,和 Python 一樣,安裝完之後可以通過 hy 命令進入 REPL 環境:

或者當做命令列指令碼執行:

儲存為 awesome.hy

接下來繼續以上面的問題為例,首先可以直接從 Python 程式碼中匯入:

如果覺得不放心,還可以直接呼叫最開始定義的方法將結果進行比較:

總結

以一個簡單的資料處理問題為例,我們經歷了 Python 函數語言程式設計從開始嘗試到“走火入魔”的整個過程。也許你還是覺得不夠過癮,想要嘗試更純粹的 FP 體驗,那麼 Haskell 將是你最好的選擇。FP 將資料看做資料流在不同函式間傳遞,省去不必要的中間變數,保證函式的純粹性…等等這些思想在資料處理過程中還是非常有幫助的(Python 在這一領域的競爭對手 R 語言本身在語法設計上就更多地受到 Lisp 語言的影響,雖然看起來語法也比較奇怪,但這也是它比較適合用於資料處理及統計分析的原因之一)。

參考

  1. Tips » 0x02-函數語言程式設計
  2. Python HOWTOs » Functional Programming HOWTO
  3. Hy’s Doc
  4. fn.py

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

Python函數語言程式設計:從入門到走火入魔

相關文章