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 step to range #702
Comments
please see: http://fr.umio.us/ranging-near-and-far/ |
Great article, in theory I agree about everything you said, in practice there's no way I'm keeping both lodash and ramda in the same project, and ramda is forcing me to maintain a lot of functionality myself. Ramda already scored big by putting functions first thus enabling partial application, but I'm starting to feel that its too purist to be practical and I've seen too many ivory tower diamonds (scheme, prolog, j...) to marvel them from far away and turn elsewhere for writing my software.
To illustrate what I'm thinking please see this article by Joel Spolsky
|
There are two answers to Joel Spolsky's cri de coeur. One is the one made by Microsoft and (as noted in the end of his article) by early-day Netscape: trying to make sure that your big tool can be configured to do whatever the user wants. The other is to follow the Unix philosophy and give a number of tools that can be snapped together to do what you need. Lo-Dash, following Underscore, seems more inclined to the former. Ramda has a definite preference for the latter. @slobodanblazeski mentions filtering. Ramda has a very simple API for
Lo-Dash's API is clearly more flexible than Ramda's. But it's significantly more complex. Ramda chooses to keep things simple and allow for the same behavior with smaller composed functions. Hence, Ramda has
That is fundamental to the philosophy of Ramda. A step parameter to the |
@CrossEye I have no clue how to wed partial application with optional arguments. My experience with common lisp optional & key makes me doubt that those things are even possible, or if it is its // end Number required
// start Number optional default 0
// step Number optional default 0
// returns [Number]
R.enum(end,start,step)
R.enum(5) <=> R.enum(5,0) <=> R.enum(5,0,1)
-> 0,1,2,3,4
R.enum(5,2) <=> R.enum(5,2,1)
-> 2,3,4
R.enum(2,5,-1)
-> 5,4,3,2 The R.enum(n) is actually the most useful since it serves as an array creator and as an replacement for for. If you want to sum first n number R.sum(R.enum(5)) Enum is also great replacement for looping when you have to do some index fiddling for(var j = 5;j < 2; j-=1.5) {
// some j index dependent code
}
// becomes
R.map(fn, R.enum(2,5,-1.5)) The single parameter enum combined with map, reduce & co replaces all those ugly for(var i=0; i <n; +=i) and its shorter to type then R.range(0,n). The two and three parameter versions are rarer but still very useful if you want to avoid for/while iteration. |
I guess using a function for the step would be more flexible, as in R.enum(2,5, R.add(1.5))
R.enum(2,20, R.multiply(1.5)) Btw, enum is somewhat similar to R.interpolate #513 R.interpolate(start / end / size)
R.interpolate(0, 100, 5) => [20, 40, 60, 80, 100]
R.interpolate(0, 1, 3) => [0.33333, 0.666666, 1.0]
R.interpolate(['cookie', 'house', 'garden'], 5) => ['cookie', 'cookie', 'house', 'house', 'garden'] |
@slobodanblazeski:
We've found no credible way to do so. In Ramda, we've handled this by having more than one function with similar behavior when we really want the ability to offer an optional parameter. It's far from ideal, but it seems the best we can do, since curried functions are so important to the style of coding Ramda is meant to support.
This is almost entirely the reverse of what I would expect from a Ramda function, I'm afraid. With only a very few obvious exceptions, every function of more than one parameter in Ramda is curried; it's how the library is intended to be used. And the parameter order for our functions is designed to take advantage of this: with those parameters less likely to change coming before those more likely to change. If we were to curry this version of (There is also a strange inconsistency between So if we were to create something like this (and I'm not convinced, by the way) my preference would be something almost the reverse of this: R.rangeTo(5) // == R.range(0, 5) == R.stepBy(1, 0, 5)
//=> [0, 1, 2, 3, 4]
R.range(2, 5) <=> R.stepBy(1, 2, 5)
//=> [2, 3, 4]
R.stepBy(-1, 5, 2)
//=> [5, 4, 3] // note the different length from the original example.
By switching to |
@CrossEye As a purist I agree with you, as pragmatist your approach is making coding inconvenient. I will add enum in my own utilities and see how it goes. But little voice inside me is starting to tell me that I'm not ramda target customer. |
That's somewhat amusing, as the reason for the currying is to be as pragmatic as we can. A recent issue for Lo-Dash discusses code like this:
(The actual issue isn't important here. It's pretty much caused by the inverse of what was discussed at great length in #452) In Ramda, the currying makes this simpler:
And if we wanted to build a reusable function for that, we would simply do
The difference between these two
is a significant part of what drives Ramda's design. |
I very rarely have to use a range with a step but something like this works for me: |
Please add step to range like lodash, very important to avoid reversal of the result and sub integer
_.range(5,2,-0.5)
[5, 4.5, 4, 3.5, 3, 2.5]
https://lodash.com/docs#range
_.range([start=0], end, [step=1])
_.range(0, -4, -1);
// → [0, -1, -2, -3]
The text was updated successfully, but these errors were encountered: