拉姆达的惯用语`obj.value = f(obj)`

问题描述 投票:3回答:2

R.evolve允许我们将对象属性替换为应用于该属性的当前值的函数的结果:

R.evolve({ count: R.inc }, { count: 1 })
   == { count: 2 }

但我经常发现我想添加一个从输入对象的多个属性计算的属性:

assocFruitTotal({ appleCount: 5, orangeCount: 3 })
  == { appleCount: 5, orangeCount: 3, fruitCount: 8 }

我提出了自己的简单实用功能:

const assocDerived = R.curry(
   (name, f, obj) => ({
      ...obj,
      [name]: f(obj)
   });

......我经常使用它:

const sumFruit = R.pipe(
   R.props(['appleCount', 'orangeCount']),
   R.sum);
const assocFruitTotal = assocDerived('fruitCount', sumFruit);

但是我使用它的绝对频率让我想知道为什么它不是原生的Ramda,因为许多其他方便的功能。这让我想知道我是否缺少一个能够实现结果的更好的习语 - 也就是说,通过添加基于其他属性组合的属性来构建对象中的细节。

我应该使用的是惯用的函数式编程结构吗?

functional-programming ramda.js
2个回答
3
投票

就个人而言,我会这样做:

const fruitCount = applySpec({fruitCount: compose(sum, values)})

fruitCount({apple: 5, orange: 3})
//=> {"fruitCount": 8}

const withFruitCount = converge(mergeRight, [identity, fruitCount]);

withFruitCount({apple: 5, orange: 3});
//=> {"apple": 5, "fruitCount": 8, "orange": 3}

如果要从总和中排除非计数属性,则可以使用pickBy

const pickCount = pickBy(flip(includes('Count')));

pickCount({appleCount: 5, orangeCount: 3, foo: 'bar'});
//=> {"appleCount": 5, "orangeCount": 3}

2
投票

让我们首先认识到obj.value = f(obj)是一个可变的赋值,因此不是一个功能性的习惯用语。这是工作中必不可少的思维方式。

在大多数情况下,将计算值存储为对象的属性是一个失误。如果appleCountorangeCount发生变化,那么就没有任何东西可以强制执行fruitCount的完整性。

fruitCount应该是一个功能,而不是财产。

const fruitCount =
  pipe
    ( props ([ 'appleCount', 'orangeCount' ])
    , sum
    )

 fruitCount ({ appleCount: 1, orangeCount: 3 }) // 4
 fruitCount ({ appleCount: 5, orangeCount: 3 }) // 8

如果我不得不猜测,这是假数据和示例问题。在某些情况下,计算值确实有意义(记忆是第一种想到的技术)但这些情况构成了例外,而不是规则。你说“我使用它的频率很高......”,所以我打赌你会在比你想要的更多的区域内做到这一点。

正如你所指出的那样,Ramda没有内置功能,所以这应该进一步表明有更多的传统方法可以解决这类问题。


面向对象的程序员会将其指定为计算属性 -

const FruitData = function (apples = 0, oranges = 0)
{ this.apples = apples
  this.oranges = oranges
}

Object.defineProperty
  ( FruitData.prototype
  , 'fruitCount'
  , { get () { return this.apples + this.oranges } }
  )
  
const f =
  new FruitData (3, 4)
  
console .log (f.fruitCount) // 7

在编写功能风格时,我们将OOP概念留在门口。开始考虑功能,你的问题就消失了 -

const FruitData = (apples = 0, oranges = 0) =>
  ({ apples, oranges })

const appleCount = fd =>
  fd.apples

const orangeCount = fd =>
  fd.oranges

const fruitCount = fd =>
  appleCount (fd) + orangeCount (fd)

console .log (fruitCount (FruitData (10, 3))) // 13
© www.soinside.com 2019 - 2024. All rights reserved.