點燈坊

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

使用 evolve() 只改變 Object 的 Value

Sam Xiao's Avatar 2021-01-29

實務上在使用 map() 時,經常是只改變某些 Property,此時當然可以在 Callback 自行組合 Object,但也可使用 Ramda 的 evolve() 使 Callback 也 Point-free。

Version

Ramda 0.27.1

map()

import { pipe, map } from 'ramda'

let data = [
  { id: 1, title: 'FP in JavaScript', price: 100 },
  { id: 2, title: 'RxJS in Action', price: 200 },
  { id: 3, title: 'Speaking JavaScript', price: 300 }
]

pipe(
  map(x => ({
    ...x,
    title: x.title.toUpperCase(),
    price: x.price * 0.8
  }))
)(data) // ?

對於原本的 data,我們想做以下加工:

  1. title 全轉成大寫
  2. price 全部打八折
  3. 其餘 property 全部保留

標準做法是使用 map() 搭配 callback,不變的 property 使用 ... 展開。

evolve000

evolve()

import { pipe, evolve, map, toUpper, multiply } from 'ramda'

let data = [
  { id: 1, title: 'FP in JavaScript ', price: 100 },
  { id: 2, title: 'RxJS in Action', price: 200 },
  { id: 3, title: 'Speaking JavaScript ', price: 300 }
]

pipe(
  map(evolve({ 
    'title': toUpper, 
    'price': multiply(0.8)
  }))
)(data) // ?

可使用 evolve() 使 map() 的 callback 能 Point-free。

evolve()
{k: (v → v)} → {k: v} → {k: v}
Object 在 key 不變的前提下,將 value 透過 function 加以改變

{k: (v → v)}:spec object,描述 object 該如何轉換,只要加上要改變的 key,與其對應要處理的 function 即可

{k: v}:要改變的 source object

{k: v}:改變結果的 target object

evolve001

Conclusion

  • 使用 evolve() 可使 map() 的 callback 語意更清楚,而且 spec object 只要描述要改變的 property 即可

Reference

Ramda, evolve()