--- tags: Functional Programming --- # 數學是有用的 - Functional Programming Functional Programming (以下簡稱 **FP** )是一種編程範式,FP 的核心思想就是透過 **function** 來解決各種問題,並且所有的 **function** 都是以「**數學函數**」為模型。 在 FP 裡 function 是有更明確的定義: > 「functions 是一種表達式,可以輸入參數,一但輸入參數後就可以**被簡化(reduced)** 或是說 **被運算(evaluated)**」 ### 更明確的來說 在 FP 裡,function 就像是**數學函式**一樣: ![FP-pic](https://i.imgur.com/90aGb8e.png) 在這個情況下來看,f 就非常符合 FP 對於 function 的規範,給定參數,不管試驗幾次都**只會出現同一個結果**: $f(1) = A$ $f(2) = B$ $f(3) = C$ 那如果是以下這種情況呢: ![FP-pic](https://i.imgur.com/6bjqePS.png) 這裡 f 不管是傳入 1、2 還是 3 都會回傳 A,這也是可以的,我們**只要確保如果傳入相同的參數**,永遠會回傳相同的值。 而我覺得 FP 最精華的概念就是這一句話,來自這個[影片](https://www.youtube.com/watch?v=e-5obm1G_FY&t=305s)。 > How we can express everything in terms of function 。 總的來說 FP 是: - Style / Pattern 一種撰寫風格 - Paradigm 一種規範 - Mindset 抽象式思維 有別於老大哥 OOP(或其他 OO 系列),FP則是近年來較為熱門的編程範式。像是 React 這套 JavaScript 框架就是使用FP來開發程式。 ## FP 的核心觀念 在 FP 中,既然要把 function 當作最核心的元件,不斷地以 function 為單位解決問替,就需要對 function 有些特別的定義,例如: ### 一等公民 (First-Class) 所謂的一等公民指的是 function 跟其他資料型別是**具有相同的地位** 也就是說 function 要可以被當成參數、回傳值,也可以賦值給變數或是存在資料結構中: ```jsx function request(onSuccess) { // onSuccess 是一個 function 被當作參數傳給 request // ... // onSuccess(data) } function add (x) { return function (y) { // function 被當作 add 的回傳值 return x + y; } } const hello = () => 'hello world!'; // function 當作 value 賦值給 hello 變數 ``` 任何一個想要實作 FP 的語言,都至少要能夠符合一等公民這個條件。 ### [Side Effect 和 Pure Function](https://hackmd.io/@ChrisW/rJT588049) 如果我們想要完全符合數學函數的型態 ---- 也就是「same input same out put」。 就必須保證 function 不會產生任何我們**預期外的不可控因素**,而這個也可以稱之為 **Side Effect**。 side effect 可以理解成「在運算的過程中,改變了系統狀態或是對外部世界進行交互」。 總歸一句話來講,跟 **output 沒關係的動作**都會被視為 Side Effect。 就例如下面的這個例子: ```javascript= let numArr = [5,3,17,2,7] function sortByDesc(arr){ return arr.sort((a,b)=>b-a) } sortByDesc(numArr) // 17 7 5 3 2 ``` 乍看之下可能是個很正常的 function,same input same output 的準則也沒錯,但因為他**改變到了外部狀態**`numArr`,所以這個 function 就擁有 Side Effect。 ```javascript= console.log(numArr) // 17 7 5 3 2 ``` 可以把它解構,讓程式不認為他們是同一個,就可以不去影響到外部物件,就不再被視為 Side Effect: ```javascript= let numArr = [5,3,17,2,7] function sortByDec(arr){ return [...arr].sort((a,b)=>b-a) } console.log(sortByDec(numArr)) // 17 7 5 3 2 console.log(numArr) // 5 3 17 2 7 ``` 相同的例子還有很多,例如使用 `A.push(B)` 不如 `[...A,...B]`、使用 `splice()` 不如 `slice()`等等很多例子,更詳細的可以去看看 [這篇](https://hackmd.io/@ChrisW/rJT588049) ,這邊只是稍微有個認知就好。 說到這邊,如果你對 side Effcet 有一些基礎認知的話,那你也知道 Pure Function 是什麼了,因為 Pure Function **就是沒有 Side Effect 的 function**。 ## why Pure 除了為了符合 FP 的定義以外,遵守這些準則有什麼好處呢,我們可以將其大概的列出來: ### 可預期 same input same output ### 容易理解 程式碼乾淨,且不用擔心會影響到外部因素,看一次就懂 ### 可組合,可分割,可重用 藉由以上兩點,就可以不斷的使用定義好的程式碼,除了符合 DRY(Dont repeat your code) 以外,還能使用 [compose & pipe](https://hackmd.io/p0NIKWclR_qOfPibQC_q9w) 打造快速開發的且愉快得 DX 體驗。 ### 可快取 (Cache) 因為 Same inpur Same output,所以我們再做類似動態規劃的運算時,就可以大大的省略重複計算的空間和效能浪費。 ### 可延遲運算 (Lazy Evaluation) 因為不會有額外side effect,因此可以使用 [Curry - 不是吃的也不會射三分](/T2ODjTcrTJW9Z2xExurFsg) 的方式放心的將程式碼包裝,組合成更強大的功能,或是把side effect排除,如下: ``` javascript= const pureHttpCall = memoize(function(url, params) { return function() { return $.getJSON(url, params); }; }); ``` > 因為我們並沒有真的發送 request,而是把 request 包裝起來,並記住這次傳入的變數,留待下次再使用,因此不算產生 side effect ### 可並行運算 我們可以並行的執行任何 function,因為 Pure Function 不會依賴外部狀態,也就是不需要共享記憶體,同時也不會有其他任何side effect,也因此不會有競爭危害 (race condition)的問題 ## FP 延伸概念 - [高階函數 HOC / HOF](https://www.notion.so/HOC-HOF-550abf8c80444711a8d1637f0e6e0e53) - [IIFE](https://www.notion.so/IIFE-01d571b82c264f4ab4c43004b9db3380) - [Closure](https://www.notion.so/Closure-b8e0ab2ca48844649bc8115ff772818e) - [Function Declarations vs. Expressions](https://www.notion.so/Function-Declarations-vs-Expressions-8f79e2300bc64f6f89634814da06ab94) > 其他大神寫好的概述可以看[這裡](https://codewords.recurse.com/issues/one/an-introduction-to-functional-programming) # 參考連結 [https://jigsawye.gitbooks.io/mostly-adequate-guide/content/ch4.html](https://jigsawye.gitbooks.io/mostly-adequate-guide/content/ch4.html) [https://totoroliu.medium.com/javascript-functional-programming-函式編程概念-e8f4e778fc08](https://totoroliu.medium.com/javascript-functional-programming-%E5%87%BD%E5%BC%8F%E7%B7%A8%E7%A8%8B%E6%A6%82%E5%BF%B5-e8f4e778fc08) [https://ithelp.ithome.com.tw/articles/10233399](https://ithelp.ithome.com.tw/articles/10233399) [https://developer.mozilla.org/zh-TW/docs/Glossary/First-class_Function](https://developer.mozilla.org/zh-TW/docs/Glossary/First-class_Function) [https://medium.com/一個小小工程師的隨手筆記/javascript-functional-programming-一文到底全紀錄-95ff19d9892](https://medium.com/%E4%B8%80%E5%80%8B%E5%B0%8F%E5%B0%8F%E5%B7%A5%E7%A8%8B%E5%B8%AB%E7%9A%84%E9%9A%A8%E6%89%8B%E7%AD%86%E8%A8%98/javascript-functional-programming-%E4%B8%80%E6%96%87%E5%88%B0%E5%BA%95%E5%85%A8%E7%B4%80%E9%8C%84-95ff19d9892) [https://jigsawye.gitbooks.io/mostly-adequate-guide/content/ch2.html](https://jigsawye.gitbooks.io/mostly-adequate-guide/content/ch2.html)