Can you create a function that takes another function and a parameter and returns a lazy stream of nested function calls?

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

Tags:

Rust