zero-functional / zero-functional

A library providing zero-cost chaining for functional abstractions in Nim.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

can it work (or be made to work) with input iterators?

timotheecour opened this issue · comments

eg:

  iterator infinite(): int {.closure.} =
    var i = 0
    while true:
      writelnL "ok1"
      yield i
      inc i

let a = infinite-->
           map(it*2).
           take(10)

Hi - OK - first I'll have to correct your code - and then it's not working anyway. You're right!
(using --> and then directly . is not a valid syntax)

So something like this would work (at the moment):

 let a = (0..100) --> map(it*2).
                      sub(0,10)

Creates @[0,...,18]

  • so sub(0,10) with 10 being exclusive is used instead of take
    Unfortunately the loop does not use break so it would run forever.

I could add the following

  • dedicated take -> uses sub (which internally uses filter)
  • check in filter for an end condition (like idx < or idx <= something) and change generated code to something like if not (idx < something): break

... or better introduce an until(cond) function that - internally - calls break when the given condition is true -> rewrite sub to use until(idx >= end) - and take uses until as well. filter itself should maybe not be changed.

fixed the "." typo, thanks.

  • so basically you're saying it should be possible to modify zero-functional to have arbitrary iterators work with map/filter/reduce/take etc primitives? (not just bounded iterators where the size is known in advance but general iterators, the analog of D's inputRange (cf http://ddili.org/ders/d.en/ranges.html as opposed to RandomAccessRange)?

eg: can this use case be supported? (in pseudo code)

echo stdin.toIterator.readLines-->
map(it.toUpper).
filter(it.canFind("FOO"))
.take(1)

which reads lazily from stdin and applies some processing, without ever requiring to convert input to an array (ie O(1) memory usage, independent of number of lines read)

  • if the above works, can arbitrary iterators be composed? what would be the simplest example of composition given 2 iterators?

Basically I want to know if it's possible to compose ranges in Nim as easily as in D
https://hub.packtpub.com/understanding-ranges/
https://www.youtube.com/watch?v=0cX1f41Fnkc Component Programming in D—Walter Bright

I have added take, takeWhile, drop and dropWhile - documentation and tests see README.md and test.nim
Currently it is available on the branch rework-iterator - you can try it out there.

So these new commands take and takeWhile - along with sub - implement a break, so processing of infinite (or very long) iterators may break.

Not sure if composing ranges can be as easily done as in D - just give me an example of something that D can and I could maybe tell you if we could do that.

In your example take is actually not necessary - I'd probably do something like
myIterator() --> map(it.toUpper()) --> find(it.find("FOO") > -1)
which returns the first occurrence where the find condition is met (in this case the condition itself is a find operation on the string) as option type. So we have either none(string) or some("my line with FOO").

@timotheecour with #22 it is now possible to create own inline iterators with --> iter(myIterName) - they are not as fancy as closure iterators and cannot be moved around to other functions, but they are efficient. See test.nim for details.

Also with the additions of take, drop and enhancements of sub that have already been merged to master, could we close this issue now?