简体   繁体   English

如何使用FP的compose()javascript将两个函数组合成1?

[英]How to compose two functions together into 1 using FP's compose() javascript?

How can I compose two functions together into 1 using FP's compose() here's live code: https://repl.it/JXMl/1 如何使用FP的compose()两个函数组合成1个实时代码: https//repl.it/JXMl/1

I have 3 pure functions: 我有3个纯函数:

// groups By some unique key
const groupBy = function(xs, key) {
  return xs.reduce(function(rv, x) {
    (rv[x[key]] = rv[x[key]] || []).push(x);
    return rv;
  }, {});
};

// ungroups the group by
const ungroup = (obj) => {
  return Object.keys(obj)
               .map(x => obj[x]);
};

// flatten array
const flatten = (arrs) => {
  return arrs.reduce((acc, item) => acc.concat(item), [])
}

And a functional utility compose function from Functional Jargon 功能实用程序由Functional Jargon组成函数

const compose = (f, g) => (a) => f(g(a))

In the end, I want a ungroupAndFlatten function created through compose() . 最后,我想通过compose()创建一个ungroupAndFlatten函数。

Along the lines of: 沿着:

const ungroupAndFlatten = compose(ungroup, flatten) // Usage doesn't work.
console.log(ungroupAndFlatten(obj)) 

Example code: 示例代码:

const arrs = [
  {name: 'abc', effectiveDate: "2016-01-01T00:00:00+00:00"},
  {name: 'abcd', effectiveDate: "2016-02-01T00:00:00+00:00"},
  {name: 'abcd', effectiveDate: "2016-09-01T00:00:00+00:00"},
  {name: 'abc', effectiveDate: "2016-04-01T00:00:00+00:00"},
  {name: 'abc', effectiveDate: "2016-05-01T00:00:00+00:00"},
]; 

const groupedByName = groupBy(arrs, 'name');

// Example Output
//
// var obj = {
//    abc: [
//      { name: 'abc', effectiveDate: '2016-01-01T00:00:00+00:00' },
//      { name: 'abc', effectiveDate: '2016-04-01T00:00:00+00:00' },
//      { name: 'abc', effectiveDate: '2016-05-01T00:00:00+00:00' }
//    ],
//    abcd: [ 
//      { name: 'abcd', effectiveDate: '2016-02-01T00:00:00+00:00' },
//      { name: 'abcd', effectiveDate: '2016-09-01T00:00:00+00:00' }
//    ]
//  }

const ungroupAndFlatten = compose(ungroup, flatten) // Usage doesn't work.
console.log(ungroupAndFlatten(groupedByName)) 

// Output:
//  var arrs = [
//    {name: 'abc', effectiveDate: "2016-01-01T00:00:00+00:00"},
//    {name: 'abcd', effectiveDate: "2016-02-01T00:00:00+00:00"},
//    {name: 'abcd', effectiveDate: "2016-09-01T00:00:00+00:00"},
//    {name: 'abc', effectiveDate: "2016-04-01T00:00:00+00:00"},
//    {name: 'abc', effectiveDate: "2016-05-01T00:00:00+00:00"},
//  ];

I believe you made a simple mistake,you've set ungroup as your f function while it is your g function: 我相信你犯了一个简单的错误,你将ungroup设置为你的f函数,而它是你的g函数:

const ungroupAndFlatten = compose(flatten, ungroup)

switch ungroup and flatten and everything will work fine 切换取消组合并展平,一切都会正常工作

Function Composition 功能组合

The function compose has a evaluation order from right to left . 函数compose具有从右到左的评估顺序。

/*
 * 1. take x
 * 2. execute g(x)
 * 3. take the return value of g(x) and execute f with it
*/
const compose = (f, g) => x => f(g(x))

There is another function called pipe which evaluates from left to right 还有另一个名为pipe函数,它从左到右进行求值

const pipe = (g, f) => x => f(g(x))

Your Code 你的守则

As already mentioned by @Nima Hakimi , you have reversed the argument order. 正如@Nima Hakimi已经提到的那样 ,你已经颠倒了争论的顺序。

To solve you problem we could 为了解决你的问题我们可以

  • switch the order of the arguments 切换参数的顺序

    \nconst ungroupAndFlatten = compose( const ungroupAndFlatten = compose(\n    flatten, 扁平化,\n    ungroup 取消组合\n) \n

     const compose = (f, g) => x => f(g(x)) const ungroup = obj => Object.keys(obj) .map(x => obj[x]); const flatten = arrs => arrs.reduce((acc, item) => acc.concat(item), []) const groupedByName = { abc: [ { name: 'abc', effectiveDate: '2016-01-01T00:00:00+00:00' }, { name: 'abc', effectiveDate: '2016-04-01T00:00:00+00:00' }, { name: 'abc', effectiveDate: '2016-05-01T00:00:00+00:00' } ], abcd: [ { name: 'abcd', effectiveDate: '2016-02-01T00:00:00+00:00' }, { name: 'abcd', effectiveDate: '2016-09-01T00:00:00+00:00' } ] } const ungroupAndFlatten = compose( flatten, ungroup ) console.log( ungroupAndFlatten(groupedByName) ) 

  • or use pipe 或使用pipe

    \nconst ungroupAndFlatten = pipe( const ungroupAndFlatten = pipe(\n    ungroup, 取消组合,\n    flatten 弄平\n) \n

     const pipe = (g, f) => x => f(g(x)) const ungroup = obj => Object.keys(obj) .map(x => obj[x]); const flatten = arrs => arrs.reduce((acc, item) => acc.concat(item), []) const groupedByName = { abc: [ { name: 'abc', effectiveDate: '2016-01-01T00:00:00+00:00' }, { name: 'abc', effectiveDate: '2016-04-01T00:00:00+00:00' }, { name: 'abc', effectiveDate: '2016-05-01T00:00:00+00:00' } ], abcd: [ { name: 'abcd', effectiveDate: '2016-02-01T00:00:00+00:00' }, { name: 'abcd', effectiveDate: '2016-09-01T00:00:00+00:00' } ] } const ungroupAndFlatten = pipe( ungroup, flatten ) console.log( ungroupAndFlatten(groupedByName) ) 

Function Composition with n Arguments 具有n参数的函数组合

And again we have 我们又一次

  • compose 撰写
    \nconst compose = (...fns) => fns.reduceRight((f, g) => (...args) => const compose =(... fns)=> fns.reduceRight((f,g)=>(... args)=> \n    g(f(...args))) 对g(f(...参数)))\n
  • pipe
    \nconst pipe = (...fns) => fns.reduce((f, g) => (...args) => const pipe =(... fns)=> fns.reduce((f,g)=>(... args)=> \n    g(f(...args))) 对g(f(...参数)))\n

Our goal is it to compose to ungroup and flatten the function groupBy , too. 我们的目标是组成以ungroupflatten的功能groupBy了。
We could try 我们可以试试

const groupByNameAndFlattenAndUngroup = compose(
    flatten,
    ungroup,
    groupBy('name', x)  // <-- this is our problem
)

but this will not work. 但这不行。 We can only compose functions with one argument.. The solution is to rewrite groupBy to a curried version: 我们只能用一个参数组合的功能。该解决方案是重写groupBy咖喱版本:

const groupBy = xs => key =>
xs.reduce((rv, x) => {
    (rv[x[key]] = rv[x[key]] || []).push(x)
    return rv
}, {})

const groupByNameAndFlattenAndUngroup = (key, xs) => compose(
    flatten,
    ungroup,
    groupBy ('name')
) (xs)

But this solution can be even shorter. 但是这个解决方案可以更短。 If we switch the order of the arguments from groupBy to groupBy = key => xs => {/*..*/} we can do: 如果我们将参数的顺序从groupBygroupBy = key => xs => {/*..*/}我们可以这样做:

const groupBy = key => xs =>
    xs.reduce((rv, x) => {
        (rv[x[key]] = rv[x[key]] || []).push(x)
        return rv
    }, {})

const groupByNameAndFlattenAndUngroup = compose(
    flatten,
    ungroup,
    groupBy ('name')
)

Working Example 工作实例

 const arrs = [ {name: 'abc', effectiveDate: "2016-01-01T00:00:00+00:00"}, {name: 'abcd', effectiveDate: "2016-02-01T00:00:00+00:00"}, {name: 'abcd', effectiveDate: "2016-09-01T00:00:00+00:00"}, {name: 'abc', effectiveDate: "2016-04-01T00:00:00+00:00"}, {name: 'abc', effectiveDate: "2016-05-01T00:00:00+00:00"}, ] const compose = (...fns) => fns.reduceRight((f, g) => (...args) => g(f(...args))) const ungroup = obj => Object.keys(obj) .map(x => obj[x]); const flatten = arrs => arrs.reduce((acc, item) => acc.concat(item), []) const groupBy = key => xs => xs.reduce((rv, x) => { (rv[x[key]] = rv[x[key]] || []).push(x) return rv }, {}) const groupByName = groupBy ('name') const groupByEffectiveDate = groupBy ('effectiveDate') const groupByNameAndFlattenAndUngroup = compose( flatten, ungroup, groupByName ) const groupBygroupByEffectiveDateAndFlattenAndUngroup = compose( flatten, ungroup, groupByEffectiveDate ) console.log( groupByNameAndFlattenAndUngroup (arrs) ) console.log( groupBygroupByEffectiveDateAndFlattenAndUngroup (arrs) ) 

您可以在单个函数中取消组合和展平。

const ungroupAndFlatten = (obj) => Object.keys(obj).reduce((a, k) => {obj[k].forEach(e => a.push(e)); return a}, [])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM