-
Notifications
You must be signed in to change notification settings - Fork 7
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
feat: maybeIterator #68
base: main
Are you sure you want to change the base?
Conversation
Could you elaborate on use cases? |
The use case for me is to terminate forwards chaining reasoning here is some of the code for it, very WIP. Below is a minimal naive example to give you an idea of what the primary logic is function getConsequents(quad: RDF.Quad): AsyncIterator<Quad> {
// Gets any new consequences that can result from adding 'quad' to the dataset with the current rules
}
// New quad to be added to the dataset
let iterator = single(quad);
// N3 Store
const store = new Store();
while ((iterator = maybeIterator(iterator)) !== null) {
// Get any new quads, by applying rules to quads generated in previous 'loop'
iterator = union(iterator.map( q => getConsequents(q) ))
// Add new quads to the store, and filter out from the iterator if already present in the store
iterator = iterator.filter(q => store.addQuad(q))
} Generally, it can be used to terminate any recursive operation that eventually stops generating new items. I recognise that this is not as not as important as the performance issues that are open, so those should still be addressed before this. |
The
I take it this is
but yes, I see the case now. Thinking perhaps to call it Although for this case (and if this is the general pattern), it could also be do {
// Get any new quads, by applying rules to quads generated in previous 'loop'
iterator = union(iterator.map( q => getConsequents(q) ))
// Add new quads to the store, and filter out from the iterator if already present in the store
iterator = iterator.filter(q => store.addQuad(q))
} while (await hasItems(iterator)) with function hasItems(iterator) {
return new Promise((resolve, reject) => {
iterator.once('error', reject);
iterator.once('data', () => resolve(true));
iterator.once('end', () => resolve(false));
});
} |
Ah yes, good catch, and indeed do-while is a better choice a lot of the time.
The current I'm also hesitant about the use of In addition I noticed some buggy behavior on a somewhat similar approach (due to the implementation of export async function maybeIterator<T>(source: AsyncIterator<T>): Promise<null | AsyncIterator<T>> {
const elem = await source.take(1).toArray();
return elem.length === 1 ? source.prepend(elem) : null;
} where I get the following failing tests
|
No, because it's after the filter has been applied? So it's just a second listener?
Yes, the better implementation is to remove the listeners yourself. |
But won't it still pull the first element out of the list before
Even then the readable API leaves the iterator in flowing mode; it requires that you explicitly call https://nodejs.org/api/stream.html#two-reading-modes For backward compatibility reasons, removing 'data' event handlers will not automatically pause the stream. Also, if there are piped destinations, then calling stream.pause() will not guarantee that the stream will remain paused once those destinations drain and ask for more data. |
Oof, you're right. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some quick thoughts.
asynciterator.ts
Outdated
let item; | ||
do { | ||
if ((item = source.read()) !== null) | ||
return source.prepend([item]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would return new AsyncIterator
whose read
method has if (item) { const rest = item; item = null; return item;} return iterator.read();
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once #65 is resolved/merged I imagine this doesn't produce much of an optimization, so not sure if it is worthwhile doing this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah; might still be a good local implementation for the quick one-element case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
local implementation for the quick one-element case.
In going to do this I realised that the logic readable
events should be roughly identical to in #59 so will wait until that is stable / merged and then we can use the same logic or refactor the necessary logic into a common abstract class.
Resolves #66
This PR introduces a
maybeIterator
which takes an iterator as input, and returns an iterator only if it is non-empty. Otherwise null is returned.Happy to accept naming suggestions on this one.
Pinging @jacosaz