Recompose: Compose function transforms values from L to R, typically this is R to L

Created on 26 Jul 2017  Â·  8Comments  Â·  Source: acdlite/recompose

I was using recompose the other day and I finally realized, since it had been working like this way all along, that the compose function was transforming values from L to R. Typically a compose function maps values from R to L. In this case compose is working more like a pipe function. I only bring this up because recompose is considered a functional React library and therefore carries over many of the semantics from the functional realm. In terms of aligning with these concepts it makes sense, at least to me, to update the function so that is works in the same way as a how a compose function has been defined in functional programming. This would require a small change to the actual function. The new function would look like:

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }
 //  All I changed was reduce to reduceRight
  return funcs.reduceRight((a, b) => (...args) => a(b(...args)))
}

I already looked into the tests and it would require updating the about 30+ tests or so.

I would like to contribute and make this change if it is deemed necessary. I didn't want to go and make a PR if the team/contributors felt otherwise. Let me know what you all think!

Most helpful comment

it does not function as expected in the sense of how components get mapped and built up

Why? In FP languages it's not rare to see composition of higher order functions which is the same as we do in recompose.
As an easy example:

const fn = compose(
 f => x => f(x * 2),
 f => x => f(x + 2),
)(x => x);
// fn(1) gives 4 as order of internal ops will be "1 *2 " then +2

and it's not the same as

const fn = compose(
 x => x * 2,
 x => x + 2,
);
// fn(1) === 6

So no confusion, it just depends on what you compose.

All 8 comments

compose in recompose defined right. Its compose and not the pipe.
read this
https://medium.com/@icelabaratory/why-recompose-uses-compose-19e6cb1430ac

I am not sure your article answers the matter. In your article you mention the function flow, a form of reduce in Lodash. I looked at Lodash's FP library and saw this:

_.pipe is an alias of _.flow and _.compose is an alias of _.flowRight

In FP terms the function signature for a compose function is (f, g)(x), which is the same as f(g(x)).

If Recompose's compose is meant to behave like a pipe function that is fine. But I have to disagree that it is defined correctly.

You can use compose function from any other library with recompose and all will work the same.
You can just take an example I provided in article
compose(x => x*2, x=> x + 2) and look at the result.

You can at least write on the paper the current definition of compose

[aF, bF, cF].reduce((a, b) => (...args) => a(b(...args)))
and write down reduce
step 1: (aF, bF) => (...args) => aF(bF(...args))
step 2: ((...args) => aF(bF(...args)), cF) => (...args) => aF(bF(cF(...args))

Now u see that it's compose?

Yep, I can see it. You're article threw me off a little. I am not sure the article is as accurate as your code snippet above. Unless I am reading it wrong.

In thinking about it some more, the compose function works as expected but in the context of Recompose it does not function as expected in the sense of how components get mapped and built up. It functions more as a pipe operator in how it is applied in Recompose. This speak more to what is going on under the hood and how functions/JSX are composed together in React. It's strange how the underlying logic can be correct and yet the implementation be something opposite.

it does not function as expected in the sense of how components get mapped and built up

Why? In FP languages it's not rare to see composition of higher order functions which is the same as we do in recompose.
As an easy example:

const fn = compose(
 f => x => f(x * 2),
 f => x => f(x + 2),
)(x => x);
// fn(1) gives 4 as order of internal ops will be "1 *2 " then +2

and it's not the same as

const fn = compose(
 x => x * 2,
 x => x + 2,
);
// fn(1) === 6

So no confusion, it just depends on what you compose.

That's interesting. I haven't seen a compose function in this sense. So in this way it inverts the arguments. That's different

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rockchalkwushock picture rockchalkwushock  Â·  3Comments

yellowfrogCN picture yellowfrogCN  Â·  3Comments

uriklar picture uriklar  Â·  4Comments

finom picture finom  Â·  3Comments

cdomigan picture cdomigan  Â·  4Comments