Suppose we have some existingIterator that iterates over elements of an arbitrary type T Now I want to get a new iterator with existingIterator with modified behavior. Think of examples like:
- Limiting the length of the original iterator, e.g.
existingIterator.take(n) . - Display elements, e.g.
existingIterator.map(modifier) - Filtering specific elements, for example
existingIterator.filter(predicate) .
In all these cases, I just want to create another iterator so that I can do something like this:
for x in existingIterator.filter(something) .map(modifier) .take(10): ...
My common problem: how can I write a generic iterator or template that accepts an existing iterator and returns a modified iterator?
The next question will be why such essential functionality is not available in the standard library - maybe I'm missing something?
Here is what I tried:
Attempt 1
Take the take(n) function as an example. My first approach was to use a regular general iterator :
iterator infinite(): int {.closure.} = var i = 0 while true: yield i inc i iterator take[T](it: iterator (): T, numToTake: int): T {.closure.} = var i = 0 for x in it(): if i < numToTake: yield x inc i for x in infinite.take(10): echo x
This compiler, but, unfortunately, it does not work: (1) the elements do not repeat correctly (are they all zero, maybe an error? ), (2) it looks like my program is stuck in an infinite loop and (3) it only works for closing iterators, which means that I cannot wrap arbitrary iterators.
Attempt 2
The restriction on closure iterators suggests that this problem actually requires a solution to the pattern.
template take[T](it: iterator(): T, numToTake: int): expr {.immediate.} = var i = 0 iterator tmp(): type(it()) = for item in it: if i < numToTake: yield item inc i tmp
It almost seems to work (i.e. compiling a template). However, if I now call for x in infinite.take(10) , I get:
`Error: type mismatch: got (iterator (): int{.closure, gcsafe, locks: 0.})`
I tried adding () to actually βcallβ the iterator, but it still doesn't work. So, it comes to the question: how do I create / return an iterator from a template?