admin管理员组文章数量:1404927
How can I convert this function position into more readable format?
funcA(argumentA, funcB(argumentA, funcC(argumentA, argumentB)))
What I'd like to achieve is something more like this:
pose(funcC, funcB, funcA)(argumentA, argumentB)
I'm using this pose function implementation:
const pose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args)))
The problem is I need argumentA in all function calls as a first parameter and every function returns a value to be passed as a second parameter to the next function. I know I could create separate function-returning functions and use them like so:
pose(funcCWithArg(argumentA), funcBWithArg(argumentA), funcAWithArg(argumentA))(argumentB)
but in my actual case there aren't only three of them, but many more and that would require some serious amount of code just to write them down. Is there a simpler way to do that?
EDIT: I can't use any external library. Only vanilla js.
How can I convert this function position into more readable format?
funcA(argumentA, funcB(argumentA, funcC(argumentA, argumentB)))
What I'd like to achieve is something more like this:
pose(funcC, funcB, funcA)(argumentA, argumentB)
I'm using this pose function implementation:
const pose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args)))
The problem is I need argumentA in all function calls as a first parameter and every function returns a value to be passed as a second parameter to the next function. I know I could create separate function-returning functions and use them like so:
pose(funcCWithArg(argumentA), funcBWithArg(argumentA), funcAWithArg(argumentA))(argumentB)
but in my actual case there aren't only three of them, but many more and that would require some serious amount of code just to write them down. Is there a simpler way to do that?
EDIT: I can't use any external library. Only vanilla js.
Share Improve this question edited Jun 19, 2017 at 8:24 zorza asked Jun 19, 2017 at 8:15 zorzazorza 2,8943 gold badges30 silver badges43 bronze badges 5- 1 Ramdajs has a function that does that ramdajs./docs/#pose – user93 Commented Jun 19, 2017 at 8:20
- @user93 From the docs you provided: "The rightmost function may have any arity; the remaining functions must be unary.". So that's not solving my problem. I need two parameters in every function. – zorza Commented Jun 19, 2017 at 8:28
- 1 @zorza pose partially applied functions with a prebound first argument. – zerkms Commented Jun 19, 2017 at 8:30
- @zerkms That's the solution I want to avoid if possible as I stated in the question. – zorza Commented Jun 19, 2017 at 8:32
- 1 @zorza First of all, this isn't function position in the original sense anymore. Sure, you could create your own binator to avoid the nested structure. However, this would disguise the control flow and make the code hard to read. The only reason why you would do this is to remain DRY. I doubt that you will need this binator often, though. So either use partially applied functions or write the function calls manually. – user6445533 Commented Jun 19, 2017 at 10:27
3 Answers
Reset to default 3Using vanilla JS,
const pose = (...fns) => (arg1, arg2) => fns.reduce((arg, f) => f(arg1, arg), arg2);
Explanation
pose
bees a function returning a function, which loops through the list of functions passed to it, passing the first argument to every function call.
Test
const sum = (a, b) => (a + b);
const mult = (a, b) => (a * b);
pose(sum, mult)(2, 3) === mult(2, sum(2, 3)); // true
It's not hard to write a function like this:
const link = (...fns) => (a, ...args) =>
fns.slice(1).reduce((val, fn) => fn(a, val), fns[0](a, ...args));
If you wanted it to be robust enough to handle errors gracefully, it would take more. But this should be a start.
You would use it like this:
const funcA = (x, y) => `funcA(${x}, ${y})`;
const funcB = (x, y) => `funcB(${x}, ${y})`;
const funcC = (x, y) => `funcC(${x}, ${y})`;
link(funcA, funcB, funcC)('argumentA', 'argumentB');
//=> "funcC(argumentA, funcB(argumentA, funcA(argumentA, argumentB)))"
You can see this in action on Runkit.
(And obviously you can do a reverse
if you want the opposite argument order.)
First create new functions that are partial applications using bind
. Then use the pose
function you already have:
const funcA = (x, y) => `A(${x}, ${y})`;
const funcB = (x, y) => `B(${x}, ${y})`;
const funcC = (x, y) => `C(${x}, ${y})`;
const pose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args)));
const partials = (...fns) => (...args) => fns.map((f) => f.bind(this, ...args));
console.log(pose(...partials(funcA, funcB, funcC)("a"))("b"));
// Output:
// A(a, B(a, C(a, b)))
UPDATE
You can also build a single function that poses the partials with the first argument passed and then calls them with the other arguments. (I think this is what you want? I wasn't 100% sure what to do with more than two arguments.)
const partialCompose = (...fns) => (...args) => pose(...partials(...fns)(args[0]))(...args.slice(1));
console.log(partialCompose(funcA, funcB, funcC)("a", "b")); // same output as above
本文标签: functional programmingCompose javascript functions with more than one argumentStack Overflow
版权声明:本文标题:functional programming - Compose javascript functions with more than one argument - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744875022a2629863.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论