# Functional Programming 都可以當你阿公了 Part 2 ###### tags: `fp` 哈囉!大家好,我是哈囉 再次感謝大家前來參加第二場 Functional Programming 的分享, 也感謝助教幫我們安排這場活動。 今天我們除了會帶到一些知識跟練習之外, 最後階段我們會進行 Live Coding, 主題是將這篇 OOP 的系統架構面試題改用 FP 的方式實作一遍。 那我們就開始今天的分享吧! ## Realworld Example 銜接上一集,我們談到了這些函式編程的知識, 誒,那這些真的能在真實世界的場景應用嗎? 那這邊就來提供一個實際案例, 我前陣子有參加鐵人賽一次出了兩個系列, 一個系列是在探討搜尋引擎的系統要如何設計, 其中我們可以看到這段程式碼, [over-engineering](https://github.com/over-engineering-run/over-engineering/blob/main/crawler/lib.ts) 這是用 deno 撰寫的一段爬蟲程式碼, 其中使用了很多等等會到的 FP 設計技巧, 像是 Curring 或是 Pipe。 接下來我的同事也提供了一段他們之前應用在資料處理的部分程式碼, 使用 Clojure 撰寫 [sentence-splitter](https://github.com/tainvecs/sentence-splitter) Clojure 是一套跑在 JVM 上的純函式編程語言, 在國外做 大數據 或是 ML 相關的公司會很有機會看到它。 其中我們也可以看到純函式的編程語言, 他一樣有 Pipeline 的設計。 另一個函式語言很常見的特色是 Pattern Matching, 雖然今天不會講到 Pattern Matching 這邊依然提供一個來自 `Ocaml` 的範例。 ```ocaml type color = Red | Black type 'a tree = Empty | Tree of color * 'a tree * 'a * 'a tree let rebalance t = match t with | Tree (Black, Tree (Red, Tree (Red, a, x, b), y, c), z, d) | Tree (Black, Tree (Red, a, x, Tree (Red, b, y, c)), z, d) | Tree (Black, a, x, Tree (Red, Tree (Red, b, y, c), z, d)) | Tree (Black, a, x, Tree (Red, b, y, Tree (Red, c, z, d))) -> Tree (Red, Tree (Black, a, x, b), y, Tree (Black, c, z, d)) | _ -> t (* the 'catch-all' case if no previous pattern matches *) ``` ## 閱讀 因為時間關係,我們沒辦法在幾堂課就把所有 FP 的知識交給大家, 那在這邊推薦幾本我曾經參考過的書籍, 給想要深入了解 FP 的觀眾。 第一本是 Kyle Simpson 的 [輕量級函式編程](https://github.com/getify/Functional-Light-JS) ,如果你有聽過 **你所不知道的 JavaScript** 一書,那這就是同一個作者。 這本裡面包含了許多入門的 FP 知識跟應用, 適合緊接著看完 You Don't Know JS 之後閱讀。 接下來是 [函式指北針](https://github.com/MostlyAdequate/mostly-adequate-guide), 這本書是 JS 社群玩 FP 的人基本上都會推薦的書, 算是 JS FP 的聖經。 裡面的知識會更接近純函式編程的概念, 適合進階一點的工程師閱讀。 再來是 Eric Elliott 的 [組合軟體](https://medium.com/javascript-scene/composing-software-the-book-f31c77fc3ddc), 這本就更進階一點, 裡面會提到像是 Lenses, Transducers 之類, 連每天在寫 FP 的人都覺得棘手的概念。 以上的書籍推薦給大家, 接著再進到正題之前,我們來上一點歷史課。 ### 一點歷史 在電腦科學的早期,連電腦都還沒問世的年代, 有兩位偉大的數學家奠定了當今電腦科學的兩大基礎, - [阿隆佐·邱奇 Alonzo Church](https://en.wikipedia.org/wiki/Alonzo_Church) 他提出了 [λ 演算 lambda calculus](https://en.wikipedia.org/wiki/Lambda_calculus) - [艾倫·圖靈 Alan Turing](https://en.wikipedia.org/wiki/Alan_Turing) 他提出了 [圖靈機](https://en.wikipedia.org/wiki/Turing_machine) 而這邊要強調 λ 演算, λ 演算直接影響到了 FP 語言的設計, 像是第一款 FP 語言 Lisp 誕生將近 60 年, 唯一比他老的高階語言就只有 Fortran,而且也只晚了一年。 相對於 IBM 設計的 Fortran, Lisp 麻省理工設計的,以前一直是麻省理工的教學語言, 直到近幾年麻省理工才換成 Python。 Lisp 的誕生也影響到後面的 FP 語言發展, 像是 Clojure 或是 Racket 都有被其影響。 > λ 演算 => Lisp => Clojure / Racket => ... Lisp 也發展了很多的變體,其中一個變體叫做 Scheme, 這套語言的其中一個特性叫 Closure, 深深的影響到了我們當今的 Javascript。 [Scheme](<https://en.wikipedia.org/wiki/Scheme_(programming_language)>) => [Javascript](https://en.wikipedia.org/wiki/JavaScript) ## Functional Programming 設計 ### [First Class Function][4] [一級函式](https://hello-kirby.hashnode.dev/mostly-adequate-guide-to-fp-chapter-02) 函式是一等公民,這是什麼意思? 就是指 函式跟其他物件一樣 沒有什麼特別。 他可以儲存在陣列裏,當成參數傳遞,賦值給變數,你想怎麼樣都行。 > 純物件導向的語言,函式必須附庸在 `class` 底下。 ```java class Obj { method() { } } ``` 而在支援一級函式的語言, 函式可以直接像這樣定義。 ```javascript const hi = (name) => `Hi ${name}`; const greeting = (name) => hi(name); ``` 像上面的 `greeting` 就是比較累贅的寫法, `hi` 已經是個函式且可以接受一個參數, 為什麼需要另外定一個函式然後只是單純把同樣的參數丟去呼叫 `hi`? ```javascript const greeting = hi; greeting("Hello"); // Hi Hello ``` ### [Higher Order Function][3] 接續著 First Class Function 的概念就是 Higher Order Function。 高階函式是指一種函式的種類,他可以: - 接收一個或多個函式做為傳入值 - 回傳函式做為其結果 > 在數學領域稱作 _算子 (Operator)_ > 簡單來說就是把某個函式映射到另一函式,例如 _微分 (Differential Operator)_。 接續著 Higher Order Function 的概念就是 **Currying**。 ### [Curring][5] [柯里化](https://hello-kirby.hashnode.dev/chapter-04-currying) 柯里化是指一種設計技巧, 它的概念非常簡單:你可以只傳一部份的參數來執行某個函式, 它會回傳一個新的函式來處理剩下的參數。 直到你把剩下的參數都填完,他才會真正執行函式的內容。 ### [Closure][6] Curring 能夠實作的前提就是程式語言必須支援 Closure 閉包 這個特性。 就是指函式可以捕捉他誕生時的執行環境,像是數值或是記憶體參照。 ### [Pipeline][1] 一個應用程式內部會有很多不同的運算處理部件, 而 Pipeline 是一種 可以將多個處理部件串連在一起 的設計模式, 透過妥善的安排,將每個部件的輸出結果傳遞到下一個部件的作為輸入, 就感覺像現實中的水管一樣。 ### [Function Composition][2] 我們將這類透過把各個小程式排列組合成一個複雜的大程式這樣的軟體設計方法, 稱作[函式組合][2]。 函式語言的各種設計基本上都是為了達成 Function Composition。 [1]: https://en.wikipedia.org/wiki/Pipeline_(software) [2]: https://en.wikipedia.org/wiki/Function_composition_(computer_science) [3]: https://en.wikipedia.org/wiki/Higher-order_function [4]: https://en.wikipedia.org/wiki/First-class_function [5]: https://en.wikipedia.org/wiki/Currying [6]: https://en.wikipedia.org/wiki/Closure_(computer_programming)