-
Notifications
You must be signed in to change notification settings - Fork 136
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Possiblity to directly use iterators ? #74
Comments
Only for pipe or for every function? |
Seems like almost every utils supporting iterable instead of arrays in iter-tools could be candidate to this change. |
This is such a bare minimum feature I am surprised it has not been implemented for this long... it basically makes this library unusable for working with ES ES in general is also evolving towards using Iterator-like objects in new APIs. Oh well, time to look for yet another alternative I guess... |
I agree this is a great addition to the library, I'm just not sure it's easy enough to be done without completely rewriting most of the library. If anyone has any suggestion on how to go about this I'd be happy to discuss it. |
i think the main question is how the typing would work. i also don't think that converting everything to be iterator-based would be "completely rewriting most of the library". only 25 out of the 132 exported functions are lazy, and for many of them it wouldn't be too hard to convert. the hardest would of course be pipe, but if we converted everything to iterators, then the pipe implementation would also be much simpler (as we can runtime-inspect whether something is an iterator) |
i think it should be possible to write a pipe that operates on iterators: R.iteratorPipe(
iterator,
R.map(x => x + 1),
R.filter(x => x > 0),
); the problem would be typing. either we let this return an array (which seems bad), or we want this to return an iterator if we want this to return an iterator, then (someone check me on this) every operator in the pipe should be a R.iteratorPipe(
iterator,
R.map.lazy(x => x + 1),
R.filter.lazy(x => x > 0),
); this is worse ergonomics. (would it be against the remeda spirit? why else do we runtime purry between datafirst and datalast, rather than having separate function names?) |
It's unlikely I'll be able to invest the time in researching this as we are currently handling mainly feature parity to allow people to migrate off Ramda and Lodash, and clean up the API for a a v2 release. My concern is that if the change requires rewriting a large chunk of the existing code then it would take a long time to make sure it's a valid solution. |
hm, please take a look at #520 – what do you think? |
Going over the pipe and purry functions lately, I have an idea for getting closer to using iterators. The main problem with the way we iterate lazily and how iterators work is that we "push" values into transformers instead of the transformer being able to pull them. What needs to be done:
After all these changes, we can try to relax the APIs for some of our functions and see if it "just works". This would allow to put any iterable at the start of a pipe at least and have its values piped. The output might still be an object/array, not a map/set, but I think that's already a pretty good API. |
Side note: This sounds like a version of Clojure's transducers. |
Hello. I published remeda-compatible npm package rotery, which expands remeda with Iterators and AsyncIterators support. |
API-wise, what do you think about a new module that exports all the functions with the same names, just for iterables and async iterables: import * as R from "remeda"
import * as Ri from "remeda/iterable"
import * as Ra from "remeda/asyncIterable"
const iterable: Iterable<T> = new Map<string, T>(...).values();
// `first` would also get type `Iterable<T>`
const first = Ri.pipe(
iterable,
Ri.first
); Note that some sync iterator helpers are standardized and shipped in Chrome and Node.js, but that async iterator helpers are held up. I don't think there are official TypeScript types for either of them yet. Also, since there is only a prototype for Iterator and not Iterable, they unfortunately only work on Iterators. But that's not something Remeda would have to worry about, so supporting all iterables would be nicer I think. |
Exporting new modules looks nice. But supporting all |
Iterator support potentially makes current lazy evaluation implementations obsolete, because iterators are always lazy. |
@somnicattus thanks for the reply! Do you think accepting/emitting |
@mb21 I reconsidered and came to the conclusion that accepting However, when it comes to emitting, |
There's also the subtle question of side effects, since depending on the input/output type combination and internal "caching" details, input iterables could be consumed multiple times and output "side effects" could be executed multiple times (if the output iterable is consumed more than once). |
Yes, Even with the fact, there are some reasons why we want to support iterators and why we can do so.
|
I would want to do something like this:
Problem is
R.first
accepts aT[]
and not anIterableIterator<T>
, so myfirst
var is of typeunknown
instead of being of typeT
;The text was updated successfully, but these errors were encountered: