javascriptramda.jscurryingfunction-compositionpointfree

Ramda apply an argument to both functions and compose them point free


I have two curried functions f and g:

f: a -> b -> c
g: a -> c -> d

I want to create h:

h: a -> b -> d

Currently I'm composing them via pipe:

const h = a => pipe(f(a), g(a));

Is there a way to do this point free?

The reason why I ask is because I want to make the code as readable as possible. In some of my cases there are more that two functions that receive initial arguments in the composition and I'm trying to avoid repeatedly passing arguments.

I tried something like:

const h = converge(pipe, [f, g]);

which for some reason doesn't work. I guess I don't understand converge correctly.

Edit:

I tried what you suggested Ori Drori, but it doesn't work.

const modulo = divisor => dividend => dividend % divisor;

const maybeReduceByModulo = modulo => number =>
  number >= 0 ? number : number + modulo;

export const maybeReducedModulo = flip(ap)(modulo, maybeReduceByModulo);
/**
 * Before:
 * export const maybeReducedModulo = divisor =>
 *   pipe(modulo(divisor), maybeReduceByModulo(divisor));
 */

Solution

  • Ramda (disclaimer: I'm a Ramda author) cannot directly offer every combinator one might need. It does contain a number of them. But for those it doesn't contain, it's often trivial to write your own version. For me the big problem is in naming. It's hard to come up with names for them, and even those who resort to bird names can only give names for a few of the infinity of possibilities.

    I can't find this one in Avaq's handy list of combinators, nor can I find :: (a -> b -> c) -> (a -> c -> d) -> a -> b -> d or :: (a -> b -> c) -> (a -> c -> d) -> (a -> b -> d) on Hoogle, which makes me suspect that this is a fairly uncommon requirement. But if it's a requirement you have, invent your own name.

    Once you've chosen a name, such combinators often write themselves.

    const foo = (f) => (g) => (x) => (y) => g (x) (f (x) (y))
    
    const f = (a) => (b) => `f (${a}, ${b})`
    const g = (a) => (c) => `g (${a}, ${c})`
    const h = foo (f) (g)
    
    console .log (h ('a') ('b'))

    And of course you can play with the signatures in various ways. Ramda's curry might help here. Perhaps we want this:

    const foo = (f, g) => (x) => (y) => g (x) (f (x) (y))
    const h = foo (f, g)
    

    or even further, this:

    const foo = curry ((f, g) => curry ((x, y) => g (x) (f (x) (y))))
    const h = foo (f, g)  // equivalent: `foo (f) (g)`
    h ('a', 'b')          // equivalent: `h ('a') ('b')`
    

    The suggestion from customcommander does work:

    const f = (a) => (b) => `f (${a}, ${b})`
    const g = (a) => (c) => `g (${a}, ${c})`
    const h = compose (apply (pipe), ap ([f, g]), of)
    
    console .log (h ('a') ('b'))
    <script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
    <script> const {compose, apply, pipe, ap, of} = R </script>

    But I think it's not nearly as understandable as the more explicit vanilla JS version.