點燈坊

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

使用 fill() 一次改變 Array 內多個 Element

Sam Xiao's Avatar 2020-03-31

ECMAScript 2015 提供了新的 Array.prototype.fill(),唯其以 Method Chianing 形式提供,且有 Side Effect 問題,Wink-fp 特別提供 Function 化的 fill() 解決此問題。

Version

macOS Catalina 10.15.4
VS Code 1.43.2
Quokka 1.0.284
Ramda 0.27.0

ECMAScript

let data = [1, 2, 3]

data.fill(0, 1, 3) // ?

ES6 的 fill() 雖然好用,但卻有幾個隱憂:

  • Data 並非最後一個 argument,因此無法 point-free 與 function composition
  • Argument 並非 currying 形式,因此無法 partial application
  • fill() 有 side effect,會影響原本 function 外的 array

其中第三點是其致命傷,一不小心就是 bug 來源。

fill000

fill()

import { clone } from 'ramda'

let data = [1, 2, 3]

let fill = v => begin => end => a => clone(a).fill(v, begin, end)

fill(0)(1)(3)(data) // ?

data // ?

可自行建立 fill(),將 array 擺到最後一個 argument,且其他 argument 都以 currying 形式提供。

先使用 clone() 斷開原本 array,如此就可安心使用 fill() 不用擔心 side effect。

fill001

Wink-fp

import { fill } from 'wink-fp'

let data = [1, 2, 3]

fill(1)(3)(0)(data) // ?

data // ?

Wink-fp 已經提供 fill() 可直接使用。

fill()
a -> Number -> Number -> [a] -> [a]
一次改變 array 內多個 element

a:要改變的值

Number:起始 index

Number:結束 index

[a]:data 為 array

[a]:回傳改變後的 array

fill002

可發現原本 array 沒有被修改。

Application

import { concat, pipe, curry } from 'ramda'
import { fill } from 'wink-fp'

let data0 = [1, 2, 3]
let data1 = [4, 5, 6]

let fillAll = fill(0)(Infinity)

let f = v => curry(pipe(
  concat,
  fillAll(v)
))

f(0)(data0)(data1) // ?

Function 化的 fill() 有什麼用呢 ? 它可輕易與其他 function 做 function composition。

若我們想將兩個 array 合併之後,並提供初始值一併初始化。

可先使用 fill(0)(Infinity) 產生 fillAll(),再使用 pipe() 組合 concat()fillAll()

fill003

Point-free

import { concat, useWith, identity } from 'ramda'
import { fill } from 'wink-fp'

let data0 = [1, 2, 3]
let data1 = [4, 5, 6]

let fillAll = fill(0)(Infinity)

let f = useWith(
  fillAll, [identity, concat]
)

f(0)(data0)(data1) // ?

也可使用 useWith() 使 f() 進一步 point-free。

fill004

Conclusion

  • Wink-fp 的 fill() 不是單純使用 invoker() 將 method 轉成 curried function 而已,還順便解決其 side effect 問題
  • Function 化的 fill() 可輕易與其他 function 做組合

Reference

MDN, Array.prototype.fill()
Ramda, concat()
Ramda, pipe()
Ramda, curry()
Ramda, useWith()
Ramda, identity()