Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-cloud-platform/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Functional programming 拉姆达语中惯用的'obj.value=f(obj)'?_Functional Programming_Ramda.js - Fatal编程技术网

Functional programming 拉姆达语中惯用的'obj.value=f(obj)'?

Functional programming 拉姆达语中惯用的'obj.value=f(obj)'?,functional-programming,ramda.js,Functional Programming,Ramda.js,R.evolve允许我们将对象属性替换为应用于该属性当前值的函数的结果: R.evolve({ count: R.inc }, { count: 1 }) == { count: 2 } 但我经常发现我想添加一个根据输入对象的多个属性计算得出的属性: assocFruitTotal({ appleCount: 5, orangeCount: 3 }) == { appleCount: 5, orangeCount: 3, fruitCount: 8 } 我提出了自己的简单实用功能:

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的原生功能,以及许多其他方便的功能。这使得 我想知道我是否遗漏了一个更好的实现结果的习惯用法——即通过添加基于其他属性组合的属性来构建对象的细节


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

我个人会这样做:

constfruitcount=applySpec({fruitCount:compose(sum,values)})
果数({苹果:5,橘子:3})
//=>{“水果计数”:8}
const with fruitCount=converge(mergeRight,[identity,fruitCount]);
果实数({苹果:5,橘子:3});
//=>{“苹果”:5,“水果数”:8,“橙色”:3}
如果要从总和中排除非计数属性,则可以使用
pickBy

const pickCount=pickBy(翻转(包括('Count'));
选取计数({appleCount:5,orangeCount:3,foo:'bar'});
//=>{“appleCount”:5,“orangeCount”:3}

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

在大多数情况下,将计算值存储为对象的属性是一个错误。如果
appleCount
orangeCount
发生更改,则无法强制执行
FrootCount
的完整性

fruitCount
应该是函数,而不是属性

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

 fruitCount ({ appleCount: 1, orangeCount: 3 }) // 4
 fruitCount ({ appleCount: 5, orangeCount: 3 }) // 8
如果非要我猜的话,这是假的数据,也是一个例子问题。在某些情况下,计算值是有意义的(记忆是第一个想到的技术),但这些情况构成了例外,而不是规则。你说“我使用它的频率很高…”,所以我打赌你在更多的领域使用它

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


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

constfruitdata=function(苹果=0,橙子=0)
{this.apples=苹果
这是桔子
}
Object.defineProperty
(FruitData.prototype)
“水果计数”
,{get(){返回this.apples+this.oranges}
)
常数f=
新数据(3,4)

console.log(f.fruitCount)//7
更通用的函数习惯用法是comonads,用于将值与其上下文一起解包。提出此建议的PR将受到Ramda团队的欢迎。扩展
evolve
或添加这样的新函数可能是有意义的。没有人保证它会被接受,但它会得到公平的听证。
applySpec
确实是
o[prop]=f(o)
,请记住,返回的
f
可能需要强制为
一元数
。我想问题是这个习惯用法是否足够普遍,以至于读者总是会立刻去摸索它。当然,我也可以写我的
assocDerived
类似
assocDerived=(name,fn)=>converge(mergeRight,[identity,applySpec({[name]:fn})])
的东西。虽然我对问题的标题有点不精确,但为了简洁起见,我认为从问题的主体可以清楚地看出,我不想改变一个对象。My
assocDerived
,如
R.assoc
R.evolve
返回输入的新克隆,并替换请求的道具。您的fruitcount已经足够明显了,但是在调用的进一步组合中,您仍然需要输入的其他部分,这是没有用的
pipe(assocDerived('fruitCount',sumFruit),o=>'你有${o.oranges}个橙子,${o.apples}个苹果,总共${fruitCount}个水果')
你的无分痴迷是
(fd=>`您有${orangeCount(fd)}个橙子,${appleCount(fd)}个苹果,总共${Frootcount(fd)}`)
是一个非常好的函数。