Array generation
So from this viewpoint (and regarding that example with squares), it's good to have also
Array.seq(from, to)
method (the name is taken from Erlang, I just frequently uses lists:seq(from, to) there):
<bikeshed>Array.range seems like an intuitive name as well.</bikeshed>
Array.seq(1, 5).map((x) -> x * x); [1, 4, 9, 16, 25]
This pattern (integer range immediately followed by map) is so common that many Schemes have a more general function that fuses the two traversals, sometimes called build-list or list-tabulate:
Array.build(n, f) ~~~ [f(0), ..., f(n-1)]
Another common and useful fusion of two traversals that's in many Schemes is map-filter or filter-map:
a.filterMap(f) ~~~ [res for [i,x] of items(a) let (res = f(x, i)) if (res !== void 0)]
I rather arbitrarily chose to accept both null and undefined here as way to say "no element" -- a reasonable alternative would be to accept only undefined as "no element".
David, I like the way you paint your bike sheds. Array.range() (or similarly functional but differently named) is definitely another one of those "oft-rerolled" solutions.
a.filterMap(f) ~~~ [res for [i,x] of items(a) let (res = f(x, i)) if (res !== void 0)]
I rather arbitrarily chose to accept both null and undefined here as way to say "no element" -- a reasonable alternative would be to accept only undefined as "no element".
Oops, I meant to say, I rather arbitrarily chose to accept only undefined and a reasonable alternative would be to accept null or undefined, i.e.:
a.filterMap(f) ~~~ [res for [i,x] of items(a) let (res = f(x, i)) if (res != null)]
I think I prefer the only-undefined version.
On 10 July 2011 22:23, David Herman <dherman at mozilla.com> wrote:
Another common and useful fusion of two traversals that's in many Schemes is map-filter or filter-map:
a.filterMap(f) ~~~ [res for [i,x] of items(a) let (res = f(x, i)) if (res !== void 0)]
I rather arbitrarily chose to accept both null and undefined here as way to say "no element" -- a reasonable alternative would be to accept only undefined as "no element".
The way I think of it is that in analogy to NaN being the Numbers that represent no number, null is the Object that represents no object, in other words a reasonable value to store to tell just that. The undefined value is by analogy the value that represents no value, so is the only value that should be a "no element".
But that might be just my way of thinking about and distinguishing the not-a-something special cases.
Agreed. I think that's a pretty common way people think about null vs undefined, and it's consistent with the language's behavior.
range.doc 'range([start,] stop[, step]) -> range object\n\nReturns a virtual sequence of numbers from start to stop by step.'
[i for i in range(10)] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[i for i in range(10, 20)] [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[i for i in range(10, 20, 2)] [10, 12, 14, 16, 18]
It seems to me we want
-
range(end), range(start, end), range(start, end, step) as in Python 3, a generator.
function range(...args) { const start = (args.length == 1) ? 0 : Number.toInteger(args[0]); const end = Number.toInteger((args.length > 1) ? args[1] : args[0]); const step = (args.length > 2) ? Number.toInteger(args[2]) : 1;
if (Number.isNaN(start) || Number.isNaN(end) || Number.isNaN(step)) { throw new TypeError("..."); }
for (let i = start; i != end; i += step) { yield i; } }
-
a way to take an iterator I and exhaust it to build an array: [x for x of I] is the comprehension form (note the paren-free for-of head). A functional form per Allen's principle would be helpful some of the time: Array.fromIterator or Array.exhaust?
-
a standard array element-key-only-and-as-integral-index (not string) and elements-only iterators: for i of indexes(array), for v of elements(array).
See harmony:iterators for more on for-of.
On 10 July 2011 22:23, David Herman <dherman at mozilla.com> wrote:
Another common and useful fusion of two traversals that's in many Schemes is map-filter or filter-map:
a.filterMap(f) ~~~ [res for [i,x] of items(a) let (res = f(x, i)) if (res !== void 0)]
I rather arbitrarily chose to accept both null and undefined here as way to say "no element" -- a reasonable alternative would be to accept only undefined as "no element".
\bikeshed{ The SML lib calls this one mapPartial, which I think is a much better name. }
On 7/11/11 at 15:09, liorean at gmail.com (liorean) wrote:
On 10 July 2011 22:23, David Herman <dherman at mozilla.com> wrote:
Another common and useful fusion of two traversals that's in many Schemes is map-filter or filter-map:
a.filterMap(f) ~~~ [res for [i,x] of items(a) let (res = f(x, i)) if (res !== void 0)]
I rather arbitrarily chose to accept both null and undefined here as way to say "no element" -- a reasonable alternative would be to accept only undefined as "no element".
The way I think of it is that in analogy to NaN being the Numbers that represent no number, null is the Object that represents no object, in other words a reasonable value to store to tell just that. The undefined value is by analogy the value that represents no value, so is the only value that should be a "no element".
The way I think of it is that NaN can be produced if an algorithm "blows up" numerically. If that happens, and the result gets stored in the array, I don't want to confuse those values with the "placeholder for purposely omitted value" value.
Cheers - Bill
Bill Frantz |"Web security is like medicine - trying to do good for 408-356-8506 |an evolved body of kludges" - Mark Miller www.periwinkle.com |
On 10.07.2011 15:54, David Bruant wrote:
It's a good question. Though, usually it's needed to initiate an array just with a simple value, so the case with a function (as a filler) was provided as just an addition. From this viewpoint, yes, perhaps it should 9 functions.
Yes, it's common way, though, that's said, usually it's needed only to fill an array with e.g. Array.fill(1)
So from this viewpoint (and regarding that example with squares), it's good to have also
Array.seq(from, to)
method (the name is taken from Erlang, I just frequently uses lists:seq(from, to) there):Array.seq(1, 5).map((x) -> x * x); [1, 4, 9, 16, 25]
Yes, also have to consider it and think.
Dmitry.