ExamplesBy LevelBy TopicLearning Paths
090 Intermediate

090 — Infinite Iterators

Functional Programming

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

  • • Use .cycle() to loop a finite iterator indefinitely
  • • Use std::iter::repeat(v) for constant infinite streams
  • • Use std::iter::from_fn(move || …) for stateful generation
  • • Use std::iter::repeat_with(move || …) for side-effecting generation
  • • Always apply .take(n) before consuming an infinite iterator
  • • Map Rust's infinite iterator combinators to OCaml's Seq recursive thunks
  • Code 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

    AspectRustOCaml
    Cycle.cycle() adapterCustom recursive Seq
    Repeatstd::iter::repeat(v)let rec aux () = Seq.Cons(v, aux)
    From closurefrom_fn(move \|\| …)Closure returning Seq.Cons(…, thunk)
    Bounding.take(n)Seq.take n
    Side effectsrepeat_with(move \|\| …)Same closure pattern
    MemoryZero-cost structsHeap 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]);
        }
    }
    ✓ Tests Rust test suite
    #[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

  • • See example.ml for implementation
  • Rust Approach

  • • See example.rs for implementation
  • Comparison Table

    FeatureOCamlRust
    Seeexample.mlexample.rs

    Exercises

  • Generate an infinite sequence of even numbers using (0..).step_by(2) and take the first 10.
  • Implement a zip_cycle that zips a finite slice with an infinite cycle: [1,2,3] zipped with [a,b,c,a,b,c,…].
  • Use repeat_with with rand::random::<f64>() to generate 100 random floats and compute their mean.
  • Create an infinite geometric sequence a, ar, ar², ar³, … using successors.
  • In OCaml, implement cycle_seq : 'a list -> 'a Seq.t and verify it produces the correct repeated sequence.
  • Open Source Repos