๐Ÿฆ€ 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

082: Type Aliases

Difficulty: Beginner Category: Type System Concept: `type Result<T> = std::result::Result<T, MyError>` โ€” shortening complex types Key Insight: Type aliases reduce verbosity without creating new types. Unlike newtypes, aliases are interchangeable with the original.
// 082: Type Aliases
// Shortening complex types with type aliases

// Approach 1: Simple aliases
type Point = (f64, f64);
type Name = String;

fn distance(p1: Point, p2: Point) -> f64 {
    ((p2.0 - p1.0).powi(2) + (p2.1 - p1.1).powi(2)).sqrt()
}

// Approach 2: Result alias (common pattern)
#[derive(Debug, PartialEq)]
enum AppError {
    ParseError(String),
    DivByZero,
}

type AppResult<T> = Result<T, AppError>;

fn parse_int(s: &str) -> AppResult<i32> {
    s.parse().map_err(|_| AppError::ParseError(format!("Not a number: {}", s)))
}

fn safe_div(a: i32, b: i32) -> AppResult<i32> {
    if b == 0 { Err(AppError::DivByZero) } else { Ok(a / b) }
}

// Approach 3: Complex type aliases
type Predicate<T> = Box<dyn Fn(&T) -> bool>;
type Transform<T> = Box<dyn Fn(T) -> T>;

fn filter_map_custom<T: Clone, U>(
    items: &[T],
    pred: &dyn Fn(&T) -> bool,
    f: &dyn Fn(T) -> U,
) -> Vec<U> {
    items.iter().filter(|x| pred(x)).map(|x| f(x.clone())).collect()
}

// io::Result pattern
type IoResult<T> = std::io::Result<T>;

fn main() {
    println!("distance: {}", distance((0.0, 0.0), (3.0, 4.0)));
    println!("parse: {:?}", parse_int("42"));
    println!("div: {:?}", safe_div(10, 3));

    let evens = filter_map_custom(
        &[1, 2, 3, 4, 5, 6],
        &|x: &i32| x % 2 == 0,
        &|x: i32| x * 2,
    );
    println!("doubled evens: {:?}", evens);
}

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

    #[test]
    fn test_distance() {
        assert!((distance((0.0, 0.0), (3.0, 4.0)) - 5.0).abs() < 0.001);
    }

    #[test]
    fn test_parse_int() {
        assert_eq!(parse_int("42"), Ok(42));
        assert!(parse_int("abc").is_err());
    }

    #[test]
    fn test_safe_div() {
        assert_eq!(safe_div(10, 3), Ok(3));
        assert_eq!(safe_div(10, 0), Err(AppError::DivByZero));
    }

    #[test]
    fn test_filter_map() {
        let result = filter_map_custom(
            &[1, 2, 3, 4, 5, 6],
            &|x: &i32| x % 2 == 0,
            &|x: i32| x * 2,
        );
        assert_eq!(result, vec![4, 8, 12]);
    }
}
(* 082: Type Aliases *)

(* Approach 1: Simple aliases *)
type point = float * float
type name = string
type age = int

let distance ((x1, y1) : point) ((x2, y2) : point) : float =
  sqrt ((x2 -. x1) ** 2.0 +. (y2 -. y1) ** 2.0)

(* Approach 2: Result alias *)
type error = string
type 'a result_t = ('a, error) result

let parse_int (s : string) : int result_t =
  match int_of_string_opt s with
  | Some n -> Ok n
  | None -> Error (Printf.sprintf "Not a number: %s" s)

let safe_div (a : int) (b : int) : int result_t =
  if b = 0 then Error "Division by zero" else Ok (a / b)

(* Approach 3: Complex type alias *)
type 'a predicate = 'a -> bool
type 'a transform = 'a -> 'a
type ('a, 'b) mapper = 'a -> 'b

let filter_map (pred : 'a predicate) (f : ('a, 'b) mapper) lst =
  lst |> List.filter pred |> List.map f

(* Tests *)
let () =
  let p1 : point = (0.0, 0.0) in
  let p2 : point = (3.0, 4.0) in
  assert (abs_float (distance p1 p2 -. 5.0) < 0.001);
  assert (parse_int "42" = Ok 42);
  assert (parse_int "abc" = Error "Not a number: abc");
  assert (safe_div 10 3 = Ok 3);
  let is_even : int predicate = fun x -> x mod 2 = 0 in
  let double : (int, int) mapper = fun x -> x * 2 in
  assert (filter_map is_even double [1; 2; 3; 4; 5; 6] = [4; 8; 12]);
  Printf.printf "โœ“ All tests passed\n"

๐Ÿ“Š Detailed Comparison

Core Insight

Type aliases give shorter names to complex types. They're transparent โ€” the compiler treats them as identical to the original. Useful for Result types, complex generics, and documentation.

OCaml Approach

  • `type 'a my_result = ('a, error) result`
  • Aliases are fully transparent
  • Can also use `type t = int` for simple aliases

Rust Approach

  • `type Result<T> = std::result::Result<T, MyError>;`
  • Common in library APIs (`io::Result<T>`)
  • No new type created โ€” just a name

Comparison Table

FeatureOCamlRust
Syntax`type alias = original``type Alias = Original;`
TransparentYesYes
Generic`type 'a t = ...``type T<A> = ...`
New type?NoNo