🦀 Functional Rust
🎬 How Rust Iterators Work Lazy evaluation, chaining, collect(), and zero-cost abstractions.
📝 Text version (for readers / accessibility)

• Iterators are lazy — .map(), .filter(), .take() build a chain but do no work until consumed

• .collect() triggers evaluation, transforming the chain into a Vec, HashMap, or other collection

• Zero-cost abstraction: iterator chains compile to the same machine code as hand-written loops

• .iter() borrows, .into_iter() consumes, .iter_mut() borrows mutably

• Chaining replaces nested loops with a readable, composable pipeline

083: Robot Simulator — State with Immutable Records

Difficulty: Intermediate Category: Records and Variants Concept: Functional state updates using record syntax and fold Key Insight: OCaml's `{ r with field = value }` maps directly to Rust's `Robot { field: value, ..self }`. Both create new values rather than mutating.
/// Robot Simulator — State with Immutable Records
///
/// Ownership: Robot is a small Copy type (all fields are Copy).
/// Methods return new robots (functional style) rather than mutating.

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Direction { North, East, South, West }

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Robot {
    pub x: i32,
    pub y: i32,
    pub dir: Direction,
}

#[derive(Debug, Clone, Copy)]
pub enum Instruction { TurnLeft, TurnRight, Advance }

impl Direction {
    pub fn turn_right(self) -> Self {
        match self {
            Direction::North => Direction::East,
            Direction::East => Direction::South,
            Direction::South => Direction::West,
            Direction::West => Direction::North,
        }
    }

    pub fn turn_left(self) -> Self {
        match self {
            Direction::North => Direction::West,
            Direction::West => Direction::South,
            Direction::South => Direction::East,
            Direction::East => Direction::North,
        }
    }
}

impl Robot {
    pub fn new(x: i32, y: i32, dir: Direction) -> Self {
        Robot { x, y, dir }
    }

    /// Returns a new Robot — functional update (like OCaml { r with ... })
    pub fn advance(self) -> Self {
        match self.dir {
            Direction::North => Robot { y: self.y + 1, ..self },
            Direction::East => Robot { x: self.x + 1, ..self },
            Direction::South => Robot { y: self.y - 1, ..self },
            Direction::West => Robot { x: self.x - 1, ..self },
        }
    }

    pub fn execute(self, instr: Instruction) -> Self {
        match instr {
            Instruction::TurnLeft => Robot { dir: self.dir.turn_left(), ..self },
            Instruction::TurnRight => Robot { dir: self.dir.turn_right(), ..self },
            Instruction::Advance => self.advance(),
        }
    }

    /// Run a sequence of instructions — fold pattern
    pub fn run(self, instructions: &[Instruction]) -> Self {
        instructions.iter().fold(self, |r, &i| r.execute(i))
    }
}

/// Version 2: Parse instruction string
impl Robot {
    pub fn run_string(self, s: &str) -> Self {
        s.chars().fold(self, |r, c| match c {
            'L' => r.execute(Instruction::TurnLeft),
            'R' => r.execute(Instruction::TurnRight),
            'A' => r.execute(Instruction::Advance),
            _ => r,
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_advance_north() {
        let r = Robot::new(0, 0, Direction::North).advance();
        assert_eq!(r, Robot::new(0, 1, Direction::North));
    }

    #[test]
    fn test_turn_sequence() {
        let r = Robot::new(0, 0, Direction::North);
        let r = r.run(&[Instruction::Advance, Instruction::TurnRight,
                        Instruction::Advance, Instruction::Advance,
                        Instruction::TurnLeft, Instruction::Advance]);
        assert_eq!((r.x, r.y), (2, 2));
    }

    #[test]
    fn test_full_rotation() {
        let r = Robot::new(0, 0, Direction::North);
        let r = r.run(&[Instruction::TurnRight; 4]);
        assert_eq!(r.dir, Direction::North);
    }

    #[test]
    fn test_string_instructions() {
        let r = Robot::new(0, 0, Direction::North).run_string("ARAALA");
        assert_eq!((r.x, r.y), (2, 2));
    }

    #[test]
    fn test_immutability() {
        let r1 = Robot::new(0, 0, Direction::North);
        let r2 = r1.advance(); // r1 is still valid (Copy)
        assert_eq!(r1.y, 0);
        assert_eq!(r2.y, 1);
    }
}

fn main() {
    println!("{:?}", r, Robot::new(0, 1, Direction::North));
    println!("{:?}", (r.x, r.y), (2, 2));
    println!("{:?}", r.dir, Direction::North);
}
(* Robot Simulator — State with Immutable Records *)

type direction = North | East | South | West
type robot = { x: int; y: int; dir: direction }
type instruction = TurnLeft | TurnRight | Advance

let turn_right = function
  | North -> East | East -> South | South -> West | West -> North

let turn_left = function
  | North -> West | West -> South | South -> East | East -> North

let advance r = match r.dir with
  | North -> { r with y = r.y + 1 }
  | East -> { r with x = r.x + 1 }
  | South -> { r with y = r.y - 1 }
  | West -> { r with x = r.x - 1 }

let execute r = function
  | TurnLeft -> { r with dir = turn_left r.dir }
  | TurnRight -> { r with dir = turn_right r.dir }
  | Advance -> advance r

let run r instructions = List.fold_left execute r instructions

let () =
  let r = { x=0; y=0; dir=North } in
  let r = run r [Advance; TurnRight; Advance; Advance; TurnLeft; Advance] in
  assert (r.x = 2 && r.y = 2)

📊 Detailed Comparison

Robot Simulator — Comparison

Core Insight

Both OCaml and Rust support "functional update" syntax for records/structs, creating a new value with some fields changed. Rust's `Copy` trait makes small structs behave like OCaml values — no ownership complications.

OCaml Approach

  • `{ r with y = r.y + 1 }` — record update syntax
  • `List.fold_left execute r instructions` — fold over instruction list
  • Pattern matching on variants for direction and instruction
  • Records are immutable by default

Rust Approach

  • `Robot { y: self.y + 1, ..self }` — struct update syntax
  • `#[derive(Copy, Clone)]` makes Robot value-like (no moves)
  • `instructions.iter().fold(self, |r, &i| r.execute(i))`
  • Methods take `self` by value (Copy), return new Robot

Comparison Table

AspectOCamlRust
Update syntax`{ r with field = val }``Struct { field: val, ..self }`
ImmutabilityDefaultVia Copy + value semantics
Fold`List.fold_left``.iter().fold()`
MethodsFree functions`impl` methods
String parsingNot shown`run_string` with char fold

Learner Notes

  • Rust struct update `..self` copies remaining fields (requires Copy or explicit clone)
  • Small enums and structs should derive Copy for functional style
  • `[Instruction::TurnRight; 4]` creates array with 4 copies (requires Copy)
  • OCaml record update and Rust struct update are remarkably similar