user1821052
user1821052

Reputation: 494

Ramda - R.both with curried predicates

My goal is to link two predicates that take the same two parameters in a R.both such that I can pass the parameters independently - i.e. curried.

Here's the repl implementation I put together:

const isXEqual = (obj1, obj2) => R.equals(obj1.x, obj2.x);
const isYEqual = (obj1, obj2) => R.equals(obj1.y, obj2.y);

const a = R.curry(isXEqual);
const b = R.curry(isYEqual);

const isBoth_Curried = R.both(a, b);

const obj1 =  {"x": 6, "y": 5};
const obj2 =  {"x": 6, "y": 5};
const obj3 =  {"x": 5, "y": 5};

isBoth_Curried(obj1, obj2); //==> true
isBoth_Curried(obj1, obj3); //==> false

isBoth_Curried(obj1)(obj2); //==> true

But: isBoth_Curried(obj1)(obj3); //==> true

Really confused - what am I missing here?

Upvotes: 2

Views: 215

Answers (3)

Scott Sauyet
Scott Sauyet

Reputation: 50807

I think Ramda's both is slightly out of sync with the majority of the library (disclaimer: I'm one of the Ramda authors.) The result of both probably should be curried to the maximum length of its arguments, as happens with its close affiliate allPass. So this should work the way you expect.

But, I think you are missing something basic, as you suggest. It doesn't matter that the inner functions are curried. They will only be called once, with all arguments:

R.both(a, b)(obj1)(obj3)                 //~> [1]

(function () {
  return a.apply(this, arguments) && a.apply(this, arguments);
})(obj1)(obj3)                           //~> [2]

(isXEqual(obj1) && isYEqual(obj1))(obj3) //~> [3]

(isYEqual(obj))(obj3)                    //~> [4]

R.equals(obj1.y, obj2.y)                 //~> [5]

R.equals(5, 5)                           //=> [6]

true

The step that's most likely tripping you up is [3], (isXEqual(obj1) && isYEqual(obj1))(obj3) ~> (isYEqual(obj))(obj3). The point is that isXEqual(obj1) is, because of your currying, a function, as is isYEqual(obj1). Both of these are truth-y, so && returns the second one.

That should explain what's going on.

I do think Ramda's both function should be updated. But you can make this work, as others have suggested, by currying the result of both.


One more point: you can write isXEqual/isYEqual more simply with Ramda's eqProps:

const isXEqual = R.eqProps('x')
const isYEqual = R.eqProps('y')

Upvotes: 3

Babakness
Babakness

Reputation: 3134

According the Ramda's source for both

var both = _curry2(function both(f, g) {
  return _isFunction(f) ?
    function _both() {
      return f.apply(this, arguments) && g.apply(this, arguments);
    } :
    lift(and)(f, g);
});

if the first parameter is a function, you are not returned a curried function.

Upvotes: 1

fredrik.hjarner
fredrik.hjarner

Reputation: 720

I think that R.both is not curried by default. If you do R.curryN(2, R.both(a, b)) then it works as one expects. Look at this REPL to see an example.

Upvotes: 1

Related Questions