使用不同的镜头依次将多个功能应用于对象

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

我想对对象中的数组执行一些更新,然后根据此更新计算另一个参数。这是我尝试过的:

import * as R from 'ramda'

const obj = {
    arr: [
        2,
        3
    ],
    result: {
        sumOfDoubled: 0
    }
};

const double = a => {
    return a*2;
}

const arrLens = R.lensProp('arr');
const res0sumOfDblLens = R.lensPath(['result','sumOfDoubled']);

const calc = R.pipe(
    R.over(arrLens,R.map(double)),
    R.view(arrLens),
    R.sum,
    R.set(res0sumOfDblLens)
);

const updatedObjA = calc(obj);
const updatedObjB = R.set(res0sumOfDblLens,R.sum(R.view(arrLens,R.over(arrLens,R.map(double),obj))),obj);


// what I want: {"arr":[4,6],"result":{"sumOfDoubled":10}}
console.log(JSON.stringify(obj)); //{"arr":[2,3],"result":{"sumOfDoubled":0}}, as expected
console.log(JSON.stringify(updatedObjA)); //undefined
console.log(JSON.stringify(updatedObjB)); //{"arr":[2,3],"result":{"sumOfDoubled":10}}, correct result but the array did not update

我意识到这两种方法都行不通;方法A归结为R.set(res0sumOfDblLens,10),这没有意义,因为它没有操作的目标对象。另一方面,方法B对基础对象进行了两次操作,而不是将第一次操作的结果作为第二次操作的输入。

我如何仅使用一个功能组合来实现这一目标;即将double()函数应用于对象的一部分,然后将该更新的对象作为输入来计算sumOfDoubled

javascript functional-programming ramda.js lenses
2个回答
0
投票

要获取更新的值和对象,以便可以设置新的总和,可以使用R.converge()

const arrLens = R.lensProp('arr');
const res0sumOfDblLens = R.lensPath(['result', 'sumOfDoubled']);

const calc = R.pipe(
  R.over(arrLens, R.map(R.multiply(2))),
  R.converge(R.set(res0sumOfDblLens), [
    R.pipe(R.view(arrLens), R.sum), 
    R.identity
  ])
);

const obj = { arr: [2, 3], result: { sumOfDoubled: 0 }};

const result = calc(obj);

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

0
投票

以及OriDrori的converge解决方案,您还可以使用其他两个Ramda函数之一。我总是喜欢converge而不是lift。它感觉更像是标准FP,其中lift非常是Ramda伪像。由于converge的某些可变参数,它并不总是能胜任。但这确实在这里,您可以编写:

converge

但是这些解决方案中的converge让我想知道是否还有更好的东西。还有。 Ramda的const calc = pipe ( over (arrLens, map (multiply (2))), lift (set (res0sumOfDblLens) ) ( pipe (view (arrLens), sum), identity ) ) 应用于函数时,有时也称为八哥组合器identity。或者说另一种方式,identity。这就是我们要在此处应用的内容。因此,使用chain,可以进一步简化:

chain
:: (a -> b -> c) -> (a -> b) -> a -> c
© www.soinside.com 2019 - 2024. All rights reserved.