如何使用 FP 的 compose() javascript 将两个函数组合成一个函数?
How to compose two functions together into 1 using FP's compose() javascript?
如何使用 FP 将两个函数组合成一个 compose()
这是实时代码:https://repl.it/JXMl/1
我有 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), [])
}
中的功能实用程序组合函数
const compose = (f, g) => (a) => f(g(a))
最后,我想要一个通过compose()
创建的ungroupAndFlatten
函数。
按照:
const ungroupAndFlatten = compose(ungroup, flatten) // Usage doesn't work.
console.log(ungroupAndFlatten(obj))
示例代码:
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"},
// ];
您可以在单个函数中取消组合和展平。
const ungroupAndFlatten = (obj) => Object.keys(obj).reduce((a, k) => {obj[k].forEach(e => a.push(e)); return a}, [])
我相信你犯了一个简单的错误,你将 ungroup 设置为你的 f 函数,而它是你的 g 函数:
const ungroupAndFlatten = compose(flatten, ungroup)
切换取消组合和展平,一切都会正常工作
函数组合
函数 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))
还有一个名为 pipe
的函数,它从 从左到右计算
const pipe = (g, f) => x => f(g(x))
您的代码
如@Nima Hakimi所述,您颠倒了参数顺序。
为了解决您的问题,我们可以
切换参数的顺序
const ungroupAndFlatten = compose(
flatten,
ungroup
)
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)
)
或使用pipe
const ungroupAndFlatten = pipe(
ungroup,
flatten
)
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)
)
具有 n
个参数的函数组合
我们又一次
- 撰写
const compose = (...fns) => fns.reduceRight((f, g) => (...args) =>
g(f(...args)))
- 管道
const pipe = (...fns) => fns.reduce((f, g) => (...args) =>
g(f(...args)))
我们的目标是将 ungroup
和 flatten
函数也组合成 groupBy
。
我们可以试试
const groupByNameAndFlattenAndUngroup = compose(
flatten,
ungroup,
groupBy('name', x) // <-- this is our problem
)
但这行不通。我们只能用一个参数组合函数。解决方案是将 groupBy
重写为 curried 版本:
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)
但是这个解决方案可以更短。如果我们将参数的顺序从 groupBy
切换为 groupBy = 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')
)
工作示例
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)
)
如何使用 FP 将两个函数组合成一个 compose()
这是实时代码:https://repl.it/JXMl/1
我有 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), [])
}
中的功能实用程序组合函数
const compose = (f, g) => (a) => f(g(a))
最后,我想要一个通过compose()
创建的ungroupAndFlatten
函数。
按照:
const ungroupAndFlatten = compose(ungroup, flatten) // Usage doesn't work.
console.log(ungroupAndFlatten(obj))
示例代码:
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"},
// ];
您可以在单个函数中取消组合和展平。
const ungroupAndFlatten = (obj) => Object.keys(obj).reduce((a, k) => {obj[k].forEach(e => a.push(e)); return a}, [])
我相信你犯了一个简单的错误,你将 ungroup 设置为你的 f 函数,而它是你的 g 函数:
const ungroupAndFlatten = compose(flatten, ungroup)
切换取消组合和展平,一切都会正常工作
函数组合
函数 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))
还有一个名为 pipe
的函数,它从 从左到右计算
const pipe = (g, f) => x => f(g(x))
您的代码
如@Nima Hakimi所述,您颠倒了参数顺序。
为了解决您的问题,我们可以
切换参数的顺序
const ungroupAndFlatten = compose( flatten, ungroup )
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) )
或使用
pipe
const ungroupAndFlatten = pipe( ungroup, flatten )
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) )
具有 n
个参数的函数组合
我们又一次
- 撰写
const compose = (...fns) => fns.reduceRight((f, g) => (...args) => g(f(...args)))
- 管道
const pipe = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args)))
我们的目标是将 ungroup
和 flatten
函数也组合成 groupBy
。
我们可以试试
const groupByNameAndFlattenAndUngroup = compose(
flatten,
ungroup,
groupBy('name', x) // <-- this is our problem
)
但这行不通。我们只能用一个参数组合函数。解决方案是将 groupBy
重写为 curried 版本:
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)
但是这个解决方案可以更短。如果我们将参数的顺序从 groupBy
切换为 groupBy = 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')
)
工作示例
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)
)