點燈坊

失くすものさえない今が強くなるチャンスよ

使用 flip() 改變 Signature

Sam Xiao's Avatar 2020-01-27

在組合 Function 時,實務上常常遇到期望的 Signature 與 Ramda 所提供的 Function 不一樣,此時可利用 flip() 加以改變。

Version

macOS Catalina 10.15.2
VS Code 1.41.1
Quokka 1.0.274
Ramda 0.26.1

Currying

let fn = discount => price => price - discount - 10

fn(20)(100) // ?

fn() 第一個 argument 為 discount,第二個 argument 為 price,除此之外,還在 function body 內多扣了 10 元。

比較特別的是 price 是放在最後一個 argument。

這個 function 就功能而言 100% 沒問題,但能否更進一步 point-free 呢 ?

flip000

Functional

import { pipe, negate, add, flip } from 'ramda'

let fn = pipe(
  negate,
  flip(add)(-10),
  add
)

fn(20)(100) // ?

由於第一個 argument 是 discount 且為 -,因此先使用了 negate()

接下來要處理 -10,由於 add() 的第一個 argument 要傳入 被減數,也就是 negate() 所計算結果,因此不能簡單使用 add(-10),因為 -10 該是 減數

我們發現期望的 add() signature 與現實剛好相反 !!

因此特別使用 flip(add)add() 的 signature 反轉,再傳入 -10,最後再 add() 迎接 price

flip()
((a, b, c, …) → z) → (b → a → c → … → z)
將 function 的第一個 argument 與第二個 argument 對調,順便 currying

((a, b, c, …) → z):原來 function

(b → a → c → … → z):回傳 argument 對調過的 curried function

flip001

__

import { pipe, negate, add, __ } from 'ramda'

let fn = pipe(
  negate,
  add(__)(-10),
  add
)

fn(20)(100) // ?

若你覺得 flip() 可讀性不高,也可改用 __,視覺上提供前一個 function 所傳入的 placeholder。

flip002

Conclusion

  • flip() 在實務上常常使用,尤其在計算類的 function 上
  • flip()__() 各有愛好者,可依可讀性自行選擇

Reference

Ramda, flip()