Hey. I've been working on a iterator library for 2 weeks.
I'm happy to announce you that made it to the stable point.
for quick introduction, you may used std/sequtils.
(-3..5).toseq.filterIt(it > 0).mapIt(it * it).max()
# gives you 25
did you noticed that I've converted a Hslice to a seq in order to operate on it? (first problem)
another problem is that it creates intermediate seq s. to demonstrate steps for above code:
@[-3, -2, -1, ..., 5] # initial seq
@[1, 2, 3, 4, 5] # filtered seq
@[1, 4, 9, 16, 25] # mapped seq
25 # max
in this example, the code created 2 intermediate seq s. in this example it's not very important but imagine you have a big seq/range/ ... and that can be both time and resource consuming.
with iterrr you can keep almost the same style, and have the benefits of imperative programming.
(-3..5) >< ifilter(it > 0).imap(it * it).imax() #25
which is almost identical to:
block:
var acc = iseqInit[typeof(default(typeof(-3..5)) * default(typeof(-3..5)))]()
block mainLoop:
for it in (-3..5):
if it > 0:
block:
let it = it * it
if not imax(acc, it):
break mainLoop
imaxFinalizer acc
you can have other names rather than it.
(-3..5) >< ifilter[n](n > 0).imap[n](n * n).imax()
"hello".pairs >< ifilter[indx, c](indx > 2).imap[_, c](ord c) # [108, 111]
let summ = 1..10 >< ireduce[acc, n](0):
acc += n
# summ: 55
1..10 >< imap(it + 1).ifilter(it > 5).do(num):
echo num
# echos 6,7,8,9,10,11 each one in new line
for more information, visit the project repo
Nice work!
The custom ident name is going to be my new favorite syntax for that pattern. I like how much clearer imap[x,y](x+y) is to read than imap((x, y) -> x + y) or worse imap(it[0] + it[1]).
One suggestion would be to provide a non-symbol variant of your macro in addition to ><. Something like iterate or iter for people or teams who dislike operators. I get it, operator fatigue is real. Also it's nice to switch between (1..20) >< ifilter(it > 5) and iter(1..20): ifilter(it > 5) forms sometimes.
Thanks for your suggestion.
I think something like iterrr or toIterrr is good. Any other suggestions would be appreciated.
I plan to add ifor for nested loops. Something like for* in Racket-lang.
Very cool to see more projects in this space.
Personally, I don't like the "bow-tie" operator. It's unprecedented and doesn't convey the sense of direction. Why not utilize the often-used |> (as seen in OCaml, F#, JS TC39, Elm, Elixir) or just reuse zero_functional -->?
For me, contrary to @elritch's experience, reusing [] for declaring idents looks poorly readable. Overloading the meaning of a basic language construct is adding to the mental overhead. I don't mind the slightly longer pseudo-closure syntax, as it's unambiguous and non-intrusive.
I also see the ability to define custom consumers (which you call "reducers"), but IMO it's only useful if the choice of iterator adapters (aka transformers) is adequate. What's the status here? Are there any plans to provide some DSL or other way for defining custom adapters?
As the final idea, some comparisons of the resulting macro expansion between iterrr and zero_functional would be very interesting to see.
This looks cool!
I agree that the “bow tie” operator does look weird and it is not very obvious IMHO. Either | > or --> as suggested by Zoom would be better, I think.
read more in readme.md of project
What's the status here? Are there any plans to provide some DSL or other way for defining custom adapters?
I think imap and ifilter is enough. unless you give me an example(s) that can change my mind
reusing [] for declaring idents looks poorly readable. Overloading the meaning of a basic language construct is adding to the mental overhead. I don't mind the slightly longer pseudo-closure syntax, as it's unambiguous and non-intrusive.
I'm kinda agree with you, let me know if you think this is intuitive,
points |> imap((x,y) => x+y) ...
I think imap and ifilter is enough. unless you give me example(s) that can change my mind
I agree that most cases are covered with those two, and some adapters can be boiled down to just a filter and a map, but not always. Some actions which require changes to the number of iterations can't be expressed with them, some require internal state, some act on multiple iterables. For example:
Looks good to me!
see new version `0.2.1` with removed i prefix and infix style custom idents =>, you can write:
(1..10) |> map(n => _ )
(1..10) |> map((a1, a2, ...) => _ )
I agree that most cases are covered with those two, and some adapters can be boiled down to just a filter and a map, but not always. Some actions which require changes to the number of iterations can't be expressed with them, some require internal state, some act on multiple iterables. For example:
why not use itertools? https://github.com/narimiran/itertools
I could use itertools for a simple case, but the main benefit of a shorter syntax for iterators is composition, i.e. building long, concise custom pipelines. If one doesn't care much about composability, templates from std or itertools are indeed good enough.
To date, the most able solution I know of is ZF, but it could benefit from more adapters and the current behaviour is a bit quirky from time to time.
UPDATE: version 1.0.4
with custom adapter and custom reducer, it's really an extensible iterator library!