In Clojure, I use a function called iterate that:
Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects
As of Rust 1.34, you can use iter::successors:
fn coltz(n: u64) -> Option<u64> {
match n % 2 {
0 => Some(n / 2),
_ => Some(3 * n + 1),
}
}
use std::iter;
fn main() {
let sequence = iter::successors(Some(10), |&v| coltz(v)).take_while(|&v| v != 1);
for v in sequence {
println!("{}", v);
}
}
12
6
3
10
5
16
8
4
2
You can repeatedly call a closure using std::iter::repeat_with():
repeat_with(move || {
let result = x;
x = f(x);
result
})
The return value is an iterator over the successive return values of the closure.
We use move
to move x
into the closure, as the current state of our iteration. Inside the closure we update x
with f(x)
and return the old value (so in the first iteration we return the original x
).
Here is a complete working example:
use std::iter::repeat_with;
fn collatz(n: u64) -> u64 {
match n % 2 {
0 => n / 2,
_ => 3 * n + 1,
}
}
fn iterate<F, X>(f: F, mut x: X) -> impl Iterator<Item = X>
where
F: Fn(X) -> X,
X: Copy,
{
repeat_with(move || {
let result = x;
x = f(x);
result
})
}
fn main() {
for i in iterate(collatz, 12).take_while(|&x| x != 1) {
println!("{}", i);
}
}
Playground