-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Add an Iterate iterator #15507
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
Add an Iterate iterator #15507
Conversation
Needless to say, I'm not too happy about the name. |
fn next(&mut self) -> Option<A> { | ||
let last_arg = unsafe { mem::zeroed() }; | ||
mem::swap(&mut last_arg, &mut self.next_arg); | ||
self.next_arg = (self.f)(last_arg.clone()); |
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.
This may not be failure-safe because any failure will attempt to drop the zeroed next_arg
field. Why not store Option<A>
?
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.
Right! I changed it to use Option (and noticed I couldn't use Option::mutate
as it takes a bare function, which maybe it shouldn't?).
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.
and noticed I couldn't use Option::mutate as it takes a bare function, which maybe it shouldn't
It takes a closure AFAICT: Option.mutate
?
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.
@huonw Oh dear, yes. I got really confused by the error message. Learning Rust every day!
It is similar but less general than the already present
|
This is nearly identical to
Also, bizarrely, it runs the closure on Overall, I don't see the point in having a near-duplicate of |
This isn't that bizarre: it makes |
@huonw That's an artifact of returning the seed, not an artifact of running the closure early. Note that Haskell's The reason that |
If this behavior is useful, perhaps we should just have a free function This could also be done as a static method on |
use std::iter::Unfold;
// FWIW this is a great example of where an `exists` existential type operator
// would be nice, so we could avoid defining the St parameter to Unfold.
// Instead I'm just going to use a non-public type.
type IterateSt<'a,T> = (|T|: 'a -> T, Option<T>, bool);
#[allow(visible_private_types)]
pub fn iterate<'a, T: Clone>(f: |T|: 'a -> T, seed: T) -> Unfold<'a, T, IterateSt<'a, T>> {
Unfold::new((f, Some(seed), true), |st| {
let &(ref mut f, ref mut val, ref mut first) = st;
if *first {
*first = false;
} else {
val.mutate(|x| (*f)(x));
}
val.clone()
})
} |
@kballard Agreed the previous implementation had bizarre characteristics around when the next value is computed. I took the liberty of using your last implementation, thank you very much. I think a free-standing function is a better fit for this. Arguably, all iterators are just specializations of |
👍 r=me unless @huonw, @alexcrichton, or @blake2-ppc disagree. |
If you ask me iterate should have its own either |
Good point. A |
Looks good to me with |
Implementation by Kevin Ballard. The function returns an Unfold iterator producing an infinite stream of results of repeated applications of the function, starting from the provided seed value.
@blake2-ppc @kballard @alexcrichton Done. |
The new iterator takes a function and produces an infinite stream of results of repeated applications of the function, starting from the provided seed value.
The new iterator takes a function and produces an infinite stream
of results of repeated applications of the function, starting from
the provided seed value.