Reputation: 43
I'm attempting to learn some functional programming in javascript using the Ramda library and I keep running into situations where I compose a bunch of functions and then have to pass the input to the result twice. The following, working code is an example:
const search = R.invoker(1, 'search');
const substring = R.invoker(2, 'substring');
const lSplit = (pat, s) => R.compose(substring(0), search(pat))(s)(s);
lSplit(/ /, 'foo bar');
lSplit
takes a regex and a string, locates the first match in the string, and returns everything to the left of the match. The last line evaluates to 'foo'. It is necessary to pass s
to the composed function twice: first to find the pattern and build the substring function and then a second time to run the composed function on the string. The code works, but the (s)(s)
seems inelegant.
I wrote a function called twice
that tidies things up a bit but doesn't really address the inelegance:
const search = R.invoker(1, 'search');
const substring = R.invoker(2, 'substring');
const twice = f => d => f(d)(d);
const lSplit = pat => twice(R.compose(substring(0), search(pat)));
lSplit(/ /)('foo bar');
Is there a cleaner or more elegant way to handle situations where you need to use your data to build your pipeline before feeding it into the pipeline?
Upvotes: 4
Views: 169
Reputation: 135367
The reason your composition seems messy is because you're composing a binary function search
with a ternary function substring
. To make matters worse, the "piped" argument takes place in the middle of the ternary function
_ search(/ /, s)
/
substring(0, /, s)
Instead of worrying about being point free, I would just write the function that expresses it best
const lSplit = (pat, s) => substring(0, search(pat,s), s);
It's not clever, but it's readable. My recommendation is to let done be done.
Upvotes: 3