Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ntheq #3190

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open

Add ntheq #3190

wants to merge 6 commits into from

Conversation

femioladipo
Copy link

Proposed

const ar = ['apple', '1A', 'math'];

R.nthEq(2, 'math', ar); //=> true
R.nthEq(-1, 'math', ar); //=> true
  • All indexing semantics would be the same as R.nth
  • All equals semantics would be the same as R.equals

Reasoning

Sometimes users of ramda maybe have their data shaped in unusual ways due to constraints out of their control. They may then need to check if the nth item in a list equals a given value. Currently, this can be achieved using R.propEq(idx, val, list). However, this is less legible than R.nthEq. In addition, by the pure presence of R.nth when R.prop can handle indices and offsets (i.e. numbers) then R.nthEq should also be present.

Finally, offset semantics are weirdly inconsistent in R.propEq when compared to R.prop. For example:

const ar = ['apple', '1A', 'math'];

R.propEq(2, 'math', ar); //=> true
R.propEq(-1, 'math', ar); //=> false

R.prop(2, ar); //=> math
R.prop(-1, ar); //=> math

@CrossEye
Copy link
Member

CrossEye commented Oct 9, 2021

Thank you for a well-written, well-reasoned PR.

I absolutely think we should unify index handling in prop and propEq (and presumably also propIs, propOr, and propSatisfies as well.) I honestly wish we had never supported negative indices anywhere, although I do recognize how useful they can be; they have made keeping various functions in sync a minor nightmare. But nonetheless, we should fix those functions to match prop.

I'm of two minds regarding adding more nth* functions.

nth was an early function in Ramda. I'm quite sure we would not add it today, as the job is well covered by prop. It seems unnecessary, and I would rather deprecate it altogether. In the very early days, we had map and a separate mapObject because our focus on simplicity meant that one function shouldn't do two things, including accepting different types. At some point we were convinced that Objects and Arrays shared a common abstraction of being Functors, and map should simply apply to all functors. I think there is something similar here, although there's no common name for them, perhaps Indexed would do. That is a real argument against nth* functions.

But on the other side, we have the handling of negative indices. It makes no sense for prop. In fact, we can't do this in any reasonable manner for both arrays and objects unless we type-check both the object and the key, and I'd rather not do that. Imagine an object whose keys were positive and negative integers representing relative positions on a timeline and whose values were, say names of events related to a person's life, with year 0 being the year of birth. Suddenly the key -1 might reasonably mean something other than "one element before the end":

const lifeline = {
  '-3': 'parents met',
  '-1': 'parents married',
  0: 'birth',
  18: 'graduated high school',
  21: 'met future spouse',
  22: 'graduated college',
  24: 'married',
  27: 'published first novel',
  length: 28
}

prop (-1, lifeline) //=> '"published first novel", but expected "parents married"

And this argues for keeping nth and possibly expanding it.

So I am torn. I would like to think about it and to hear arguments for and against.

What do you think, @femioladipo ? And @ramda/core ?

@femioladipo
Copy link
Author

First off thanks I’m happy to contribute.

Next, you raised some good points, and I agree with most. However, I've got a few suggestions. Give me to this afternoon to write something up.

@customcommander
Copy link
Member

It is possible I haven't fully grasped the specifics of this proposal but as far as I can tell we could do something similar with pathEq:

pathEq([2], 'math', ['apple', '1A', 'math']);
//=> true

pathEq([-1], 'math', ['apple', '1A', 'math']);
//=> true

@CrossEye
Copy link
Member

@customcommander:

as far as I can tell we could do something similar with pathEq:

But that's still a problem, as I'm concerned, all the prop* functions should have similar behavior to their path* equivalents. Ideally propFoo (name, ...rest) should behave identically to pathFoo([name], ...rest).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants