In school we have tasked to build an implementation of the lodash method flowRight!
In the spec it mentions:
Takes an arbitrary amount of functions and returns a new function that uses its arguments and calls the provided functions from right to left (last to first). The argument for each function (except the first) is determined by the return value of the function to its right. The call to the function returned by flowRight evaluates to the return value of the left most function.
And this is an example they give:
e.g.
var sayHello = function (name) {
return 'Hello, ' + name;
},
addExclamation = function (s) {
return s + '!';
},
smallTalk = function (s) {
return s + ' Nice weather we are having, eh?';
};
var greetEnthusiastically = flowRight(addExclamation, sayHello);
greetEnthusiastically('Antonio');
// --> returns 'Hello, Antonio!'
//(sayHello is called with 'Antonio',
// addExclamation is called with 'Hello, Antonio')
I feel like I understand what is going on in a static example like this example demostrates.
function (func1, func2) {
return function(value) {
return func1(func2(value));
}
}
Guess I am having a hard time wrapping my brain around doing it in a loop, which I think you'll need. This is my implementation so far.
var flowRight = function (...args) {
var Func;
for(var i = args.length - 2; 0 > i; i--) {
function Func(value) {
return args[i](args[i + 1](value));
}
}
return Func;
};
Any help will be appreciated!
No need for a loop. This uses ES6 if that is permitted.
This uses spread
, rest
, and reduce
const flowRight = (...functions) => functions.reduce((a, c) => (...args) => a(c(...args)));
Example below
var sayHello = function (name) {
return 'Hello, ' + name;
},
addExclamation = function (s) {
return s + '!';
},
smallTalk = function (s) {
return s + ' Nice weather we are having, eh?';
}
const flowRight = (...functions) => functions.reduce((a, c) => (...args) => a(c(...args)))
var greetEnthusiastically = flowRight(smallTalk, addExclamation, sayHello)
console.log(greetEnthusiastically('Antonio'));
To flow from right to left you can use the ...spread
with .reduceRight(x, y)
I've commented the code below to try and explain how this all works together.
const sayHello = function (name) {
return 'Hello, ' + name;
};
const addExclamation = function (s) {
return s + '!';
};
const smallTalk = function (s) {
return s + ' Nice weather we are having, eh?';
}
// function that takes functions and then
// returns a function that takes a value to apply to those functions in reverse
const flowRight = (...fns) => val => fns.reduceRight((val, fn) => {
// return the function and pass in the seed value or the value of the pervious fn.
// You can think of it like the following.
// 1st pass: sayHello(value) -> "Hello, " + value;
// 2nd pass: addExclamation("Hello, $value") -> "Hello, $value" + "!";
// 3rd pass: smallTalk("Hello, $value!") -> "Hello, $value!" + ' Nice weather we are having, eh?'
// ... and so on, the reducer will keep calling the next fn with the previously returned value
return fn(val)
// seed the reducer with the value passed in
}, val);
var greetEnthusiastically = flowRight(smallTalk, addExclamation, sayHello);
console.log(greetEnthusiastically('Antonio'));
right-to-left composition
const flowRight = (f, ...more) => x =>
f == null ? x : f(flowRight(...more)(x))
const upper = s =>
s.toUpperCase()
const greeting = s =>
`Hello, ${s}`
const addQuotes = s =>
`"${s}"`
const sayHello =
flowRight(addQuotes, greeting, upper)
console.log(sayHello("world"))
// "Hello, WORLD"
left-to-right composition
const flowLeft = (f, ...more) => x =>
f == null ? x : flowLeft(...more)(f(x))
const upper = s =>
s.toUpperCase()
const greeting = s =>
`Hello, ${s}`
const addQuotes = s =>
`"${s}"`
const sayHello =
flowLeft(addQuotes, greeting, upper)
console.log(sayHello("world"))
// HELLO, "WORLD"
using reduceRight
We can use reduceRight
to easily implement flowRight
-
const flowRight = (...fs) => init =>
fs.reduceRight((x, f) => f(x), init)
const upper = s =>
s.toUpperCase()
const greeting = s =>
`Hello, ${s}`
const addQuotes = s =>
`"${s}"`
const sayHello =
flowRight(addQuotes, greeting, upper)
console.log(sayHello("world"))
// "Hello, WORLD"
using reduce
Or we can use reduce
to easily implement flowRight
-
const flowLeft = (...fs) => init =>
fs.reduce((x, f) => f(x), init)
const upper = s =>
s.toUpperCase()
const greeting = s =>
`Hello, ${s}`
const addQuotes = s =>
`"${s}"`
const sayHello =
flowLeft(addQuotes, greeting, upper)
console.log(sayHello("world"))
// HELLO, "WORLD"
The idea in the function written below is to return a function that will iterate over the list of functions and store result from each call and return it at the end.
function flowRight(...args) {
return function (initial) {
let value = initial;
for (let i = args.length - 1; i >= 0; i--) {
value = args[i](value);
}
return value;
};
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With