[FP] Currying
原文:https://medium.com/hannah-lin/fp-currying-3de006469b14
寫得特別好,一看就懂,不得不留存一下。
太多初學者以為會 map、 reduce 就代表會 Functional Programming 了!真的是大錯特錯啊。FP 世界真的古老又博大精深,雖然不算好入門,但熟了之後一定會愛上的,因為好處實在比 OOP 多太多!
三年前其實自己第一次聽到 Currying 腦中也只浮現以下 XD


認真研究後也是有看沒懂。但過了三年習慣用 Functional Programming 寫程式後就發現其實 Currying 概念不斷貫穿在 FP 中,希望這篇能用淺顯的敘述來介紹它。
喔對了為什麼會叫 Currying 是因為是因為這個方法的概念的建立者叫做 Haskell Curry。
What’s currying?
Transforms a function with multiple arguments to a chain of function applications with one argument each
簡單來說就是 “把接受多個參數的函數變換成接受一個單一參數就叫做 Currying” 還是不懂沒關係,直接來看例子,以下是一個單純做變數相加的函式
const add = (a, b) => a + b;
add(1, 2) // 3改成 Currying 後就會變
const add = a => b => a + b;
add(1)(2) // 3 // ---- below is common way -------
const add1 = add(1)
add1(2) // 3
你會發現 Currying 一次只接受 “一個” 參數


它的原理也很簡單,就利用 closure 特性,將 f(a) 存放在 g 中 ,待最後參數 b 傳入,完成運算 g(b)。
Why use currying?
- DRY (Don’t Repeat Yourself ): 有別於以往一個函式處理所有事情,Currying 可以將程式碼依功能拆解成更小單元,有助於重複利用 (這也是 FP 精華之一)
- 一次處理一個參數,提高程式的彈性和可讀性
以下是一個判斷你分數有沒有有 Pass 的簡單函式

你會發現一直需要丟重覆的參數 Pass 、Fail 跟平均分數 0.2,那換成 Currying 呢?

是不是乾淨多了呢!
Properties, Arguments & Currying
運用 Currying 特性其實也可以變出很多花樣
Q 我想要讓 add([x, y]) == add(x, y)

Q 想要 add(x, y) = add(y, x)

Q 改寫 [‘a’, ‘b’, ‘c’].slice(0, 2) 成 slice(1)(3)([‘a’, ‘b’, ‘c’])
const slice = start => end => array => array.slice(start, end)運用 Currying 改寫以下函式系列
input: words(“Jingle bells Batman)
output: [‘Jingle’, ‘bells’, ‘Batman’]
const _curry = f => a => b => f(a, b) 
input: sentences([“Jingle bells Batman smells”, “Robin laid an egg”])
output: [[‘Jingle’, ‘bells’, ‘Batman’, ‘smells’], [‘Robin’, ‘laid’, ‘an’, ‘egg’]]

input: max([323,523,554,123,5234])
output: 5234

Partial application vs. currying
常看到有人把這兩個當成同樣東西,事實是他們的確很像,也都是利用 closure 特性但卻是不一樣的

// Currying
const add = a => b => c => a + b + c;
add(1)(2)(3) // 6// Partial application
const add = a => (b, c) => a + b + c;
add(1)(2, 3) // 6
- currying: Creates a chain of unary functions
- Partial application: operates with functions of any arity
╔════════════════╦═════════════════════════════════════════════╗
║ ║ currying ║ Partial application ║
╠════════════════╬════════════════════╬════════════════════════╣
║ arity ║ 1 ║ variable (f, ...args)) ║
╠════════════════╬════════════════════╬════════════════════════╣
║ bind arguments?║ No ║ Yes ║
╚════════════════╩════════════════════╩════════════════════════╝所以最大不同就是 currying 只接收一個 Arity,而 Partial application 可以接受多個
Arity?
the number of arguments of a function
f( a ) // arity: 1
f( a, b ) // arity: 2
f(...args) // arity: 0Partial application example

後記
這一篇本來應該要出現在今年 it 邦幫忙鐵人賽中的,但離開賽實在太久,以我這種愛拖延的個性可能到開賽才開始準備… ,還不如早點發在這逼自己預備啊~對了本文很多範例都是參考 FrontendMaster 的 Hardcore Functional Programming in JavaScript ,覺得講的很有深度,推薦大家看













留言
張貼留言