// 086: Custom Iterator with State
// Approach 1: Counter iterator
struct Counter {
current: i32,
step: i32,
}
impl Counter {
fn new(start: i32, step: i32) -> Self {
Counter { current: start, step }
}
}
impl Iterator for Counter {
type Item = i32;
fn next(&mut self) -> Option<i32> {
self.current += self.step;
Some(self.current) // infinite
}
}
// Approach 2: Fibonacci iterator
struct Fib { a: u64, b: u64 }
impl Fib {
fn new() -> Self { Fib { a: 0, b: 1 } }
}
impl Iterator for Fib {
type Item = u64;
fn next(&mut self) -> Option<u64> {
let val = self.a;
let next = self.a + self.b;
self.a = self.b;
self.b = next;
Some(val)
}
}
// Approach 3: Collatz sequence (finite)
struct Collatz { n: u64, done_: bool }
impl Collatz {
fn new(start: u64) -> Self { Collatz { n: start, done_: false } }
}
impl Iterator for Collatz {
type Item = u64;
fn next(&mut self) -> Option<u64> {
if self.done_ { return None; }
let val = self.n;
if self.n == 1 {
self.done_ = true;
} else if self.n % 2 == 0 {
self.n /= 2;
} else {
self.n = 3 * self.n + 1;
}
Some(val)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_counter() {
let v: Vec<i32> = Counter::new(0, 2).take(3).collect();
assert_eq!(v, vec![2, 4, 6]);
}
#[test]
fn test_counter_negative() {
let v: Vec<i32> = Counter::new(10, -3).take(4).collect();
assert_eq!(v, vec![7, 4, 1, -2]);
}
#[test]
fn test_fibonacci() {
let fibs: Vec<u64> = Fib::new().take(8).collect();
assert_eq!(fibs, vec![0, 1, 1, 2, 3, 5, 8, 13]);
}
#[test]
fn test_collatz() {
let v: Vec<u64> = Collatz::new(6).collect();
assert_eq!(v, vec![6, 3, 10, 5, 16, 8, 4, 2, 1]);
}
#[test]
fn test_collatz_one() {
let v: Vec<u64> = Collatz::new(1).collect();
assert_eq!(v, vec![1]);
}
}
(* 086: Custom Iterator with State *)
(* Approach 1: Counter using mutable ref *)
let make_counter start step =
let n = ref (start - step) in
fun () -> n := !n + step; Some !n
(* Approach 2: Fibonacci via Seq *)
let fibonacci () =
let rec aux a b () = Seq.Cons (a, aux b (a + b)) in
aux 0 1
let take_seq n s =
let rec aux n s acc =
if n <= 0 then List.rev acc
else match s () with
| Seq.Nil -> List.rev acc
| Seq.Cons (x, rest) -> aux (n - 1) rest (x :: acc)
in
aux n s []
(* Approach 3: Collatz sequence iterator *)
let collatz_seq start =
let rec aux n () =
if n = 1 then Seq.Cons (1, fun () -> Seq.Nil)
else Seq.Cons (n, aux (if n mod 2 = 0 then n / 2 else 3 * n + 1))
in
aux start
(* Tests *)
let () =
let counter = make_counter 0 2 in
assert (counter () = Some 2);
assert (counter () = Some 4);
assert (counter () = Some 6);
let fibs = take_seq 8 (fibonacci ()) in
assert (fibs = [0; 1; 1; 2; 3; 5; 8; 13]);
let collatz = List.of_seq (collatz_seq 6) in
assert (collatz = [6; 3; 10; 5; 16; 8; 4; 2; 1]);
Printf.printf "โ All tests passed\n"