Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Ramda, how do you compose against binary functions?

Ramda provides a case-sensitive equals with R.equals, however I want a case-insensitive equality test. Ramda also provides R.compose, but in the Ramda composition, it's assumed the left most argument is unary.

What I want to do is something like

R.compose( R.equals(...), R.toLower )

But, I want to compose the R.toLower on the binary function R.equals?

Is there a method to accomplish this? Types likes

(b->b->c) -> (a->b) => (a->a->c)

What I want is something like Haskell's Data.Function.on which is defined as

on b u x y runs the binary function b on the results of applying unary function u to two arguments x and y. From the opposite perspective, it transforms two inputs and combines the outputs.

like image 793
NO WAR WITH RUSSIA Avatar asked Feb 04 '26 23:02

NO WAR WITH RUSSIA


1 Answers

EDIT: R.useWith comes very close to what you're looking for:

Accepts a function fn and a list of transformer functions and returns a new curried function. When the new function is invoked, it calls the function fn with parameters consisting of the result of calling each supplied handler on successive arguments to the new function.

So you can define your function like this:

const equalsi = R.useWith(R.equals, [R.toLower, R.toLower]);

Example:

const equalsi = R.useWith(R.equals, [R.toLower, R.toLower]);

const check = (a, b) => console.log(`${a} = ${b}?`, equalsi(a, b));

check('aaa', 'aaa');
check('aaa', 'aa');
check('aAa', 'aaa');
check('aaa', 'aAa');
check('aba', 'aaa');
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.0/ramda.min.js"></script>

If you wanted something equivalent to the Haskell on function that you mention, you could define one as follows:

const on = (b, u) => R.useWith(b, [u, u]);
const equalsi = on(R.equals, R.toLower);

const check = (a, b) => console.log(`${a} = ${b}?`, equalsi(a, b));

check('aaa', 'aaa');
check('aaa', 'aa');
check('aAa', 'aaa');
check('aaa', 'aAa');
check('aba', 'aaa');
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.0/ramda.min.js"></script>

Previous answer:

There may be a more elegant way to do this, but this works:

const equalsi = R.unapply(R.compose(
    R.apply(R.equals),
    R.map(R.toLower)
));

Breaking it down:

// [] -> Boolean
// Takes an array of two strings and returns true if they are equal
R.apply(R.equals)

// [] -> Boolean
// Takes an array of two strings, converts them to lowercase, and returns true
// if those lowercase strings are equal
R.compose(R.apply(R.equals), R.map(R.toLower))

// String -> String -> Boolean
// Takes two strings, converts them to lowercase, and returns true if those lowercase
// string are equal
R.unapply(R.compose(R.apply(R.equals), R.map(R.toLower)));

You could also define your on function in terms of Ramda functions and then use that:

const on = (b, u) => R.unapply(R.compose(R.apply(b), R.map(u));

const equalsi = on(R.equals, R.toLower);
like image 58
JLRishe Avatar answered Feb 06 '26 14:02

JLRishe