顯示具有 pure function 標籤的文章。 顯示所有文章
顯示具有 pure function 標籤的文章。 顯示所有文章

2015年11月9日 星期一

函數式編程介紹 ( 1 / 2 )

函數式編程的專有名詞篇


純函數 ( Pure Function )給同樣輸入參數,就會回傳同樣結果的函數,而且沒有任何可觀察到的副作用。Pure Function 的例子:sin(x)。非 Pure Function 的例子:getChar()、random()、還有許多類別中的 member function。從數學上來理解,純函數就是一個數學函數,一個輸入會對到一個輸出。

純函數的特點:
  1. Portable / Self-Documenting :完全是自給自足的 ( self contained ),沒有外在的依賴 (Dependency)。
  2. 可暫存 ( Cacheable ):把計算值暫存的技巧被稱作 memorization,可以用來避免重複計算,加速程式。
  3. 好測試 ( Testable ):不需要管上下文和呼叫順序就可以測試。
  4. 適合平行處理、純函數是線程安全的 ( thread safe )。
  5. 引用透明 ( Referential Transparent ):一個引用透明的運算式指的是 如果這個運算式可以被他的值 (回傳值) 替換而不影響整個程式的行為。簡單講就是有可交換性啦。
  6. 可以熱抽換 ( Hot-Loading ):因為不依賴外部的狀態。

副作用 ( Side Effect )如果一個函數或運算式 ( expression ) 被說有副作用,這指的是它改變了一些狀態 ( states ) 或是 跟呼叫他的函數或外在世界,有可觀察到的互動。舉例來說,一個函數可能會改變全域變數或函數的靜態變數、改變傳進來的參數、引發例外 ( exception )、列印資料到螢幕或是呼叫了其他有副作用的函數。如果有了副作用,函數的行為會受到歷史、執行順序的影響。這樣子一來,想要理解或除錯有副作用的函式會較難,因為就必須要了解他的上下文 ( Context ) 和執行歷史。

顯式 ( Explicit ):形容函數与外界交換資料只有一個唯一管道——参數和回傳值。和顯式的相反是隱式 ( Implicit )。

一級函數( First-Class Function ):指的是語言支援把 Function 當成第一類公民,可以支援一般變數的操作,像是把 Function 當成變數傳給另外一個 Function。

Lambda Function:Lambda 運算式是匿名函式,可用來建立委派或運算式樹狀架構類型。

形式系統 ( Formal System ):形式系統可以的廣泛地被定義為任何基於數學模型的、良好的抽象思考的系統 ( system of abstract thought )。

Currying:這個技巧能把接受多參數的函數轉換為多個連續呼叫的單一參數函數。

閉鎖 ( Closure ) / MDN:Closure 是可以使用獨立 / 自由變數的函數。換句話說,Closure 記得它實體化時的環境變數。

PS:專有名詞那邊引用了很多別人的解釋,可以點前面的連結進去看完整版。

-----------------------------------------------------------------------------------------


函數式編程簡介篇

函數式編程的的哲學就是假設副作用 ( side effect ) 是不正確行為的主要原因。所以努力想要控制和管理副作用,經常的解法就是把純函數、單子和不純的函數 ( impure function ) 分開來管理。另外鼓勵大家多寫純函數。我們對待資料要像玩戲法般,一直傳來傳去、禁止使用狀態 ( state ) 和副作用。剛剛這段文字有提到很多專有名詞,但這樣子怎麼寫程式?這邊我開始介紹一個新工具叫 柯里化 ( currying )。

Currying:
Currying 把任何的函數轉換成 一連串只做單一事情的函數,各個擊破。

Curring的概念是簡單的。它讓你呼叫函數 A 時可以傳比預期還少的參數。然後這個函數 A 會回傳函數 B函數 B 需要的參數是先前沒傳進函數 A 的參數。所以整個流程是:

函數A (x, y) 可以等價於下面這段
-------------------------------------
函數B = 函數A (x)
函數B (y)

先前傳進去函數 A 的參數會利用閉鎖 ( Closure ) 的方式變成函數 B 的環境變數。看完上面這段解說,一定會想這什麼鬼東西?來看看 這邊的例子 會容易理解的多。利用這個技巧,就可以選擇一次傳所有參數或是把參數分幾次傳給數個函數。

lodash提供了把函數 curry化的工具,用法:

var divide =           function (x,y) { return x / y } 可以被改寫成
-----------------------------------------------------
var divide = curry( function (x,y) { return x / y } );

之後就可以被這樣呼叫

divide ( x ) ( y );

或是

var xDividedBy = divide ( x );
tenDividedBy ( y );

PS:這工具的名字是為了紀念一個美國數學家 --- Haskell Curry,跟咖哩沒有關係。

接下來我們看另外一個工具 代碼組成( compose )。

組合 / 組成 / 合成 ( compose )
Composition 把許多函數用管子 ( pipe ) 連接起來,變成一個新個函數。


f, g 都是函數,x 在它們之間被傳遞。
注意g函數的參數是 x、f函數的參數是 g函數的回傳值。
較常用在 f & g 都吃同一類參數的時候 (ex: 字串)。


例子:變大寫和去空白函數 = compose (變大寫函數, 去空白函數)

因為有了一級函數、Currying、組合,Pointfree 風格變得流行了起來,指的是函數呼叫時不用提到它要處理的資料。例如:

var snakeCase = function ( word ) {
      return word.toUpperCase( ).replace( /\s+/ig, '_' );


可被改寫成
-----------------------------------------------
var snakeCase = compose ( replace( /\s+/ig'_' ), toLowerCase );

用組合形成新函數就不用提到資料 --- 也就是之前寫法中的 word

Pointfree的編程風格可以讓我們移除不需要的名字 (names),讓我們保持簡潔 ( concise ) 和一般化 / 泛型 ( generic )。但要小心 Pointfree 是個雙面刃,有時會把原來的目的變得模糊。

( 以上是書本前五章的內容,其他待續... 後面有點硬,不知道什麼時候會看。)

---
這篇文介紹得很好 函數式編程

2015年11月8日 星期日

Javascript 中的函數式編程 (a talk @ ReactiveConf 2015)

影片:Functional Programming in Javascript By Daniel Steigerwald 

Daniel 是 google 前員工、也是 https://github.com/este/este 這個 React + Redux + immutable.js Starter Kit 的作者,在 Github 上有 1800 顆星。

我認為函數式編程 ( Functional Programming ) 將在明年成為主流。像在 C++11 和 Java 8 中已經開始有 lambda function。我接下來聊我已經用在 Production 的東西。我認為函數式編程已經在前端的世界已經被 React 引入。

什麼是函數式編程?
沒有什麼神秘的東西,到處都是純函式 ( Pure functions everywhere )、不可變的數值 ( Immutable values )、用組成而不用繼承 ( composition over inheritance )、紀錄代替類別 (records over classes)、處理好副作用 ( taming side-effects )。我覺得 functional programming 有點像是人工智慧,聽起來有點酷、有點奇怪,但當你了解了它以後,就只是無聊、很平常的寫程式而已。

為什麼要函數化 ( functional )? 
因為軟體正在吃掉這個世界,它必須要做到最好。函數式編程已經被證明,比較少臭蟲 ( less bugs)、較不複雜 ( less complexity )、程式碼更可讀 ( more readable code ) 和更好的效能 ( more performance )。

物件導向程式設計 ( OOP ) 有什麼問題?
沒有問題,只是很難、常被誤用,而且有時是難以避免的。整個物件導向程式設計的模式 (paradigm) 是基於「送訊息給物件是唯一跟狀態 ( state ) 互動的方法」,因此狀態就會被分散。於是在分散式系統中狀態的一致的難度是跟世界和平一樣的 XD


物件導向程式設計 和 函數式編程的設計模式比較
Scott Wlaschin是很好的講者,不像我鼓勵大家去聽他的演講。

在 OOP 中,每次方法在某個實體上被呼叫其實就是副作用。副作用很難被追蹤、被理解,沒有人喜歡驚喜。驚喜在生活中是好的,但驚喜在程式碼裡面沒有任何好的地方。我們被教導要用繼承,但他是陷阱,程式碼會不夠彈性、很難之後改變。設計模式最難的是如何幫這些模式取名字,動詞偽裝成名詞。策略、工廠、Commands...

React 中最耀眼的原則是函式組成法 ( function composition )。

純函數 ( pure function ) vs 髒類別 (dirty class)

純函數沒有任何副作用。他很難去違反只負責一件事的原則 ( single responsibility principle) 因為純函數只有一個明顯的目的 --- 把輸入轉成輸出。所以測試就變得超簡單。

類別是髒的。互叫一個簡單的類別函式,就會改變它。誰做的?為什麼做?我們永遠不知道 ( 直到我們 debug 後)...

推薦這本 github 上的書適當的函數式編成指南 ( 在 github 上有 6000 顆星)


如果你不理解這個程式,沒關係。我也不懂。在函數式編程裡它等於 ( (4 + 0) * 2) + (4 * 2)
Immutable.js
不可變資料一旦被建立就不能被改變,這使得更簡單的應用程式開發,不用預防性的回傳複製品,更可以使用間單的邏輯來達到進階的 memoization 和改變偵測。一個針對不變資料的可變 API 並不改變原來資料,而是總是產生新的資料。
   - 和 原生的 Javascript array 有很相似的 API
   - 保持永遠的不可變 (List, stack, map, orderedMap, Set, OrderedSet and Record)
   - 非常快

---
PS:作者講的不多,上面很多都是照投影片上大量文字打的。