-
-
Notifications
You must be signed in to change notification settings - Fork 95
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
number: flip S.sub argument order, and remove S.dec and S.inc #391
Conversation
You rang? The broader problem is: Is there a way in JS to handle non-commutative infix operators converted to prefix that preserves readable semantics? IMO that answer is "no", having been on this snipe hunt several times. Given that my answer to the above is "no", and that the new JS lambda syntax is so compact, my recommendation is not to have infix-to-prefix functions on the API at all. Use a lambda. I'd be happy to see such functions removed from the ramda API. Sorry if this $0.02 is not much help. |
A lambda works fine for A lambda does not work for We have no choice but to define |
Another option I've been kicking around this morning is to have an S.lt(2)(1) // true
S.lt(2, 1) // true
S.infix(2, S.lt, 1) // false You could even curry it to give the semantics of the current batch of binary functions we've discussed. S.infix(2, S.lt)(1) // false
// or potentially
S.sectionl(2, S.lt)(1) // false
S.sectionr(2, S.lt)(1) // true
|
I thought that might run into difficulty deeper into the |
|
What did you mean by this?
I started working on a new programming language a few days ago. It will bring together the things I most appreciate about Haskell (curried functions) and Lisp (uniform syntax). Here's a teaser: > S.map (- 1) [1, 2, 3]
[0, 1, 2]
> S.filter (S.gte (S.Just 0)) [S.Nothing, S.Just -1, S.Just 0, S.Just 1]
[Just 0, Just 1] This may be possible with the help of a macro: > S.filter (>= S.Just 0) [S.Nothing, S.Just -1, S.Just 0, S.Just 1]
[Just 0, Just 1]
Interesting idea, Gabe. |
@davidchambers, you could instead have a family of three related functions S.sub(3, 2) // 1
// infix
S.in_(3, sub, 2) // 1
// left section
S.l_(3, sub)(2) // 1
// right section
S.r_(sub, 3)(2) // -1 The reason I chose The benefit of this approach is that you don't need any special cases for associative binary functions. They can just be vanilla, uncurried functions. |
That simple lambdas would run afoul of the type system in more constrained contexts. |
That's nice! I like the switch you made to the
I believe you missed my intended point, @buzzdecafe, which does not concern type checking. |
My thinking is that |
Oh, I see. It's not currently possible to define uncurried functions with sanctuary-def, but we could certainly address this limitation.
I prefer the middle column to the right column. The downside of the approach proposed in #388 is that we'll end up with lots of Gabe, are you happy to proceed with the plan set out in #388, or would you prefer to give the |
David, I've revised my proposal again after playing around with Haskell this evening.
I've changed Also note that
Looking at the table, my proposal appears a little clunky. But I rarely fully qualify functions that I import in my own work and am more likely to use them as follow. const {compose, _in, _l, _r, div, gte, lt, sub, Just, Nothing} = S;
const lt5 = _r(lt, 5);
const _3minus = _l(3, sub);
compose(lt5, _3minus)( 12 / 3 ); // true
_in(Just(12), gte, Nothing); // true I'd like to see if anyone else has opinions on this before moving on. It's been a point of contention in Sanctuary as well as Ramda for quite some time. It even tripped me up today using lodash/fp 😊 I'm going to reference this comment in #239 and ramda/ramda#1497 to see what others think. |
This is the best proposal I've yet seen in this never-ending debate. I will try to make a PR for Ramda using this, unless you want to do it. |
@gabejohnson: so the proposed |
@tycho01, I don't know what to tell you. Sanctuary, Ramda and Folktale all currently have that behavior. Vanilla lodash does as well. lodash/fp flips the argument order. fnuc changes the order depending on the number of arguments passed. Additionally, LISPs prefix everything and have the same operator order I think that if the "section" functions are highlighted and well explained before encountering any associative, non-commutative binary functions, things should be fine. That is, as long as there is total consistency. |
@CrossEye go for it. I doubt I'll have time for a few weeks anyway. |
bad8f5f
to
f70867b
Compare
//. R.inc('XXX'); | ||
//. // => NaN | ||
//. R.add(2, true); | ||
//. // => 3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this example even more. 🤣
//. // | ||
//. // The value at position 1 is not a member of ‘FiniteNumber’. | ||
//. // | ||
//. // See https://github.com/sanctuary-js/sanctuary-def/tree/v0.11.0#FiniteNumber for information about the sanctuary-def/FiniteNumber type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like having to remember to update this each time we upgrade the sanctuary-def dependency.
I'm going to be bold and merge this pull request. One of the undocumented differences between Ramda and Sanctuary is the system of governance. I believe a benevolent dictatorship with a circle of trusted advisors and open two-way communication with the community is an excellent system of governance for open-source software projects. One advantage of this approach is that difficult decisions can be made without unanimous agreement. I've been thinking about this problem for a couple of years now. The approach put forward here and in #388 is the first I've found satisfactory during this time. I'll exercise my discretion as benevolent dictator by merging this pull request. |
Problem: Defining subtract N functions is awkward. There are currently two options:
Furthermore, the intuitive approach is incorrect:
Solution: Flip
S.sub
argument order. The intuitive approach then works as expected:Problem with the solution: It's surprising for
S.sub(7, 2)
to evaluate to-5
rather than5
.Solution to the problem with the solution: Make
S.sub
unary.S.sub(7, 2)
is then a type error:One can use
S.sub_
in situations in which a binary subtraction function is required.This pull request also removes
S.dec
andS.inc
.S.dec
was included in the library in large part becauseS.sub(S.__, 1)
andS.add(-1)
are awkward.S.inc
was included for symmetry. In a world in whichS.sub(1)
defines the subtract 1 function,S.dec
does not warrant inclusion, in my view. Do others agree?/cc @CrossEye, @buzzdecafe