invariants for partial application#836
Conversation
There was a problem hiding this comment.
This is necessary because R.add(1)() does not throw, but R.inc() must throw to satisfy the first invariant.
Were we to replace the first invariant with one that states that for any function f where f.length > 0, f() is equivalent to f, we wouldn't need the _curry1 decorator here.
|
Does this mean that |
Yes. If one wants a function which always returns undefined one should use |
|
Then I'd consider this a breaking change. From the
This would no longer be true. What is the purpose of throwing the error? You said yourself that you didn't like it. |
Absolutely.
I disagree. > R.sortBy(R.identity, ['foo', 'bar', 'baz'])
['bar', 'baz', 'foo']In every situation where
I'll let @buzzdecafe answer that. :) |
|
Sort by is only one example and we do use |
|
What sort of higher-order function would call the provided function with no arguments? I can imagine this being done to trigger side effects or to coordinate control flow (as with Mocha's |
Must I use it in a higher order function?
I'm confused. What is the purpose and vision of ramda? This is from an earler readme (v0.8.0). While it is not there anymore, it is what I read when I came to ramda and how I understood this project:
Today in the readme we have:
I always saw ramda as different than say fantasy-land or haskell stuff. fantasy-land dictates things such as "there must be a thing like I guess I am just saying that I think it is nice to aim for purity, a lot of good comes out of it. My own code has certainly improved by ramda inspired writing but I consider it to be counter productive sometimes to focus to much on purity and not in practicality. And I don't understand the need to throw errors in these cases but lets see what @buzzdecafe has to say... |
|
i may be the only one who thinks throwing on zero arguments is correct behavior: however, i do not think |
|
@buzzdecafe Would that mean that point 1 from @davidchambers should be:
IFAIK this is already true. |
|
@TheLudd yes, that looks right to me. however, i expect that the counter will be that partially applying one value to a function of length 2 yields a function of length 1, which will then throw on zero arguments. from that POV, i am more sympathetic to not throwing on zero args. |
There was a problem hiding this comment.
This really does nothing like testing 'any other value than R.__', but unless we get into property-based testing, we can't really do that.
|
This is going to take a little bit of reflection. My initial reaction is positive. I like the idea of conforming to straightforward laws, and I like these laws. I also share @davidchambers' objection to throwing the TypeError. It might be time to revisit that. But the concern @buzzdecafe expressed recently on another issue about pointlessness is even stronger here. We're taking a hit on performance (no idea yet how big) in order to fulfill certain abstract laws, to get a consistency that sounds of more academic than practical concern. To me the key word there is 'sounds'. I can easily imagine scenarios where these things come back to bite us if they're not done right, and recognize just how hard they would be to work around for a user of the library. Hence a little time for reflection is worthwhile. I'm less concerned about the issue raised by @TheLudd. unless, and I didn't notice it in the implementation, this sneaks back in the idea that |
|
For far too long I've had on the back burner an almost completed Philosophy of Ramda document. I will try to dust it off soon, complete it, and publish it. In it I talk about what I see by "practical". @buzzdecafe is not happy with that term in our mantra, because to pretty much everyone, "practical" means "what will help me". But I think we can be more specific than that. Part of how we end up being practical is by being extremely consistent. If you know how everything is going to work, there's no surprises. To this end, I'll end up losing one of my favorite functions (#834) because it doesn't really fit; it mutates user data. For the same reason, we do not include @davidchambers' suggestion is one more way to add some consistency to the library. In this case, it has to be balanced against a competing pragmatic concern: we will have to see how it affects performance. But that sort of trade-off is essential. Choosing whether or not to add a I will try to get that document published this weekend if not before. |
929b075 to
18afbb7
Compare
|
@buzzdecafe in #106 (comment):
Ramda's curried functions do not "take 1 arg & return 1 result". They take some number of arguments and return one value. If
We can generalize this: applying a curried function
We're currently adding an exception to the |
Pointless, yes -- but more importantly, wrong. The question boils down to whether we want to throw when we have detected something wrong, or let the user persist in his folly. I'm not willing to fight for it. I think @CrossEye is also of the opinion that
|
We could change the predicate to |
|
right, i've already registered my discomfort with redundant placeholder, so no need to rehash that here. |
|
I wrote
I finally published the damned thing: http://fr.umio.us/the-philosophy-of-ramda/ |
|
hang on. if we have |
🎉
That's right. |
|
i see. seems wasteful, but i am interested to see where this leads. |
|
Where do we stand on this pull request in its current form? |
|
🌿 |
18afbb7 to
d5751dd
Compare
invariants for partial application
I set out to 🍛 the few functions not yet curried and found myself tackling a larger issue.
I'd like to guarantee consistent handling of arguments to Ramda functions. This pull request defines three invariants:
fwheref.length > 0, applyingfto no arguments results in a TypeError being thrown. (For the record, I don't like this behaviour. I'd prefer to return a function equivalent tof.)fwheref.length > 0, applyingftoR.__gives a function equivalent tof.fwheref.length > 1, applyingfto any value other thanR.__gives a functiongwith lengthf.length - 1. All three invariants hold forgand all "descendants" ofg.