R.evolve
lets us replace object properties with the result of a function applied to that property's current value:
R.evolve({ count: R.inc }, { count: 1 })
== { count: 2 }
But I frequently find I want to add a property calculated from multiple properties of input object:
assocFruitTotal({ appleCount: 5, orangeCount: 3 })
== { appleCount: 5, orangeCount: 3, fruitCount: 8 }
I came up with my own simple utility function:
const assocDerived = R.curry(
(name, f, obj) => ({
...obj,
[name]: f(obj)
});
... and I use it a lot:
const sumFruit = R.pipe(
R.props(['appleCount', 'orangeCount']),
R.sum);
const assocFruitTotal = assocDerived('fruitCount', sumFruit);
But the sheer frequency with which I use this makes me wonder why it's not native to Ramda, as so many other convenient functions are. And that makes me wonder whether I'm missing a better idiom that achieves the outcome -- that is, building up detail in an object by adding properties based upon combinations of other properties.
Is there an idiomatic functional programming construct I should be using instead?
答案 0 :(得分: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}
答案 1 :(得分:2)
让我们开始认识到obj.value = f(obj)
是一个可变的赋值,因此不是一开始就有用的习语。这是工作中的命令式思维。
在大多数情况下,将计算值作为属性存储在对象上是错误的。如果appleCount
或orangeCount
发生更改,则没有任何东西可以强制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