-
-
Save milesrout/b72afd9594d81ea6e7f8 to your computer and use it in GitHub Desktop.
namespace std { | |
using numeric_range = struct { min,max,stride: int }; | |
// provide an implementation of the Range concept for numeric_range | |
impl Range<numeric_range> { | |
using iterator = struct { min,stride: int }; | |
using sentinel = struct { max: int }; | |
let begin(nr: numeric_range) => iterator{nr.min, nr.stride}; | |
let end(nr: numeric_range) => sentinel{nr.max}; | |
let next(iter: iterator) => iterator{iter.min + iter.stride, iter.stride}; | |
let current(iter: iterator) => iter.min; | |
let __neq__(iter: iterator, sent: sentinel) => (iter.min < sent.max); | |
}; | |
let range(min,max,stride=1: int) => numeric_range{min, max, stride}; | |
} | |
// prints "1\n2\n3\n4\n5\n6\n7\n8\n9\n10" | |
let main(args: []string) { | |
for x in range(0,10).map(i => i + 1) { | |
"%d\n".printf(x); | |
} | |
} |
using numeric_range = struct { start, end, step, current: int };
let range(start, end, step=1: int) => numeric_range.new(start, end, step, end == start ? null : start);
let next(range: numeric_range) {
if (range.current != range.end) {
return numeric_range.new(range.start, range.end, range.step, range.current + range.step);
}
numeric_range.new(range.start, range.end, range.step, null); // indicate that the iteration is over (use whatever you want, this is just a simple example)
}
let map(range: numeric_range, fn: (int) -> int) {
foreach (let x in numeric_range) {
yield fn(x);
}
}
let main(args: []string) {
foreach (let x in range(0, 10)) {
printf("%d ", x); // 0 1 2 3 4 5 6 7 8 9
}
foreach (let x in range(10, 20).map(i => i + 5)) {
printf("%d ", x); // 15 16 17 18 19 20 21 22 23 24
}
}
Define foreach as something like
while (it.current) {
fn(it.current);
it = it.next();
}
where it is a templated iterator which conforms to the .next and .current behaviour
and fn is the code block of the foreach
I think so long as a template specialization exists for the object being used as an iterator, it should be fine
If it doesnt exist, throw errors
Range
is a concept, and concepts use CamelCase
names, as do type parameters.
nr
was used then I changed it.
impl
indicates that a particular type (in this case, numeric_range
) fulfils the contract of a given concept (in this case Range
).
Ranges are things that you can call begin
and end
on to get an iterator and a sentinel respectively, which might be the same type. e.g. for a raw array, the begin is a raw pointer to the first element and end is a raw pointer to the last element. for a string, the begin is a pointer to the first element and the length seen so far, while the end is just the length.
map
is a generic function that works the same for all Range
s:
let map<R,T>(r: R, f: R.value_type -> T)
where Range<R> && T != void
{
let first = r.begin;
let last = r.end;
while (first != last) {
yield f(t);
}
}
or similar.
You've mixed up your case with the Range on line 5
You have nr defined but never use it
what is the point of the impl syntax?