090 — Infinite Iterators
Tutorial
The Problem
Create infinite iterators using Rust's standard library combinators: cycle (repeat a finite sequence forever), repeat (emit one value forever), from_fn (stateful generator), and repeat_with (side-effecting generator). Always bound with .take(n) before collecting. Compare with OCaml's Seq-based infinite sequence representations.
🎯 Learning Outcomes
.cycle() to loop a finite iterator indefinitelystd::iter::repeat(v) for constant infinite streamsstd::iter::from_fn(move || …) for stateful generationstd::iter::repeat_with(move || …) for side-effecting generation.take(n) before consuming an infinite iteratorSeq recursive thunksCode Example
#![allow(clippy::all)]
// 090: Infinite Iterators — cycle, repeat, from_fn
#[cfg(test)]
mod tests {
#[test]
fn test_cycle() {
let v: Vec<i32> = [1, 2, 3].iter().copied().cycle().take(7).collect();
assert_eq!(v, vec![1, 2, 3, 1, 2, 3, 1]);
}
#[test]
fn test_repeat() {
let v: Vec<i32> = std::iter::repeat(42).take(4).collect();
assert_eq!(v, vec![42, 42, 42, 42]);
}
#[test]
fn test_from_fn() {
let mut n = 0i32;
let v: Vec<i32> = std::iter::from_fn(move || {
let v = n;
n += 1;
Some(v)
})
.take(5)
.collect();
assert_eq!(v, vec![0, 1, 2, 3, 4]);
}
#[test]
fn test_repeat_with() {
let mut c = 0;
let v: Vec<i32> = std::iter::repeat_with(move || {
c += 1;
c * c
})
.take(4)
.collect();
assert_eq!(v, vec![1, 4, 9, 16]);
}
}Key Differences
| Aspect | Rust | OCaml |
|---|---|---|
| Cycle | .cycle() adapter | Custom recursive Seq |
| Repeat | std::iter::repeat(v) | let rec aux () = Seq.Cons(v, aux) |
| From closure | from_fn(move \|\| …) | Closure returning Seq.Cons(…, thunk) |
| Bounding | .take(n) | Seq.take n |
| Side effects | repeat_with(move \|\| …) | Same closure pattern |
| Memory | Zero-cost structs | Heap thunks |
The key rule with infinite iterators: never call collect() or sum() without a prior .take(n) or another bounding consumer. Rust's type system does not prevent infinite loops — the programmer must ensure termination.
OCaml Approach
OCaml's cycle wraps a list as a Seq and restarts from the list when the current pointer is Nil. repeat is let rec aux () = Seq.Cons(x, aux). counter_from uses a mutable ref and a thunk. The implementations mirror Rust's semantics — the difference is structural: Rust combinators are zero-cost structs; OCaml uses heap-allocated thunks.
Full Source
#![allow(clippy::all)]
// 090: Infinite Iterators — cycle, repeat, from_fn
#[cfg(test)]
mod tests {
#[test]
fn test_cycle() {
let v: Vec<i32> = [1, 2, 3].iter().copied().cycle().take(7).collect();
assert_eq!(v, vec![1, 2, 3, 1, 2, 3, 1]);
}
#[test]
fn test_repeat() {
let v: Vec<i32> = std::iter::repeat(42).take(4).collect();
assert_eq!(v, vec![42, 42, 42, 42]);
}
#[test]
fn test_from_fn() {
let mut n = 0i32;
let v: Vec<i32> = std::iter::from_fn(move || {
let v = n;
n += 1;
Some(v)
})
.take(5)
.collect();
assert_eq!(v, vec![0, 1, 2, 3, 4]);
}
#[test]
fn test_repeat_with() {
let mut c = 0;
let v: Vec<i32> = std::iter::repeat_with(move || {
c += 1;
c * c
})
.take(4)
.collect();
assert_eq!(v, vec![1, 4, 9, 16]);
}
}#[cfg(test)]
mod tests {
#[test]
fn test_cycle() {
let v: Vec<i32> = [1, 2, 3].iter().copied().cycle().take(7).collect();
assert_eq!(v, vec![1, 2, 3, 1, 2, 3, 1]);
}
#[test]
fn test_repeat() {
let v: Vec<i32> = std::iter::repeat(42).take(4).collect();
assert_eq!(v, vec![42, 42, 42, 42]);
}
#[test]
fn test_from_fn() {
let mut n = 0i32;
let v: Vec<i32> = std::iter::from_fn(move || {
let v = n;
n += 1;
Some(v)
})
.take(5)
.collect();
assert_eq!(v, vec![0, 1, 2, 3, 4]);
}
#[test]
fn test_repeat_with() {
let mut c = 0;
let v: Vec<i32> = std::iter::repeat_with(move || {
c += 1;
c * c
})
.take(4)
.collect();
assert_eq!(v, vec![1, 4, 9, 16]);
}
}
Deep Comparison
Core Insight
take(n) limits infinite iterators to finite consumption — laziness makes infinite sequences practical
OCaml Approach
Rust Approach
Comparison Table
| Feature | OCaml | Rust |
|---|---|---|
| See | example.ml | example.rs |
Exercises
(0..).step_by(2) and take the first 10.zip_cycle that zips a finite slice with an infinite cycle: [1,2,3] zipped with [a,b,c,a,b,c,…].repeat_with with rand::random::<f64>() to generate 100 random floats and compute their mean.a, ar, ar², ar³, … using successors.cycle_seq : 'a list -> 'a Seq.t and verify it produces the correct repeated sequence.