๐Ÿฆ€ Functional Rust

022: Range

Difficulty: 1 Level: Foundations Create a list of all integers between two values โ€” ascending or descending.

The Problem This Solves

Generating integer sequences is one of the most basic programming tasks: page numbers, loop indices, test data, coordinate grids. Given `start=4` and `end=9`, produce `[4, 5, 6, 7, 8, 9]`. If `start > end`, produce the reverse: `[9, 8, 7, 6, 5, 4]`. Python has `range(4, 10)` built in, and JavaScript uses `Array.from({length: n}, (_, i) => start + i)`. These are fine but don't auto-detect direction โ€” you need `range(9, 3, -1)` for descending in Python, or a separate implementation. Rust's range syntax `(start..=end).collect()` is native and zero-cost โ€” it generates values lazily and collects into a `Vec` only when needed. Adding direction detection is two lines. And since Rust's ranges are typed, the compiler catches mixing `i32` and `usize` before they cause bugs.

The Intuition

In Python: `list(range(4, 10))` (ascending) or `list(range(9, 3, -1))` (descending) In JavaScript: `Array.from({length: end - start + 1}, (_, i) => start + i)` Rust uses the `..=` syntax for inclusive ranges (both ends included). `(4..=9)` creates a `RangeInclusive<i64>` iterator. Calling `.collect()` on it gathers all values into a `Vec<i64>`. For descending ranges, Rust's `(end..=start).rev()` reverses the iteration. The function detects which direction to use based on `start <= end`.

How It Works in Rust

fn range(start: i64, end: i64) -> Vec<i64> {
 if start <= end {
     (start..=end).collect()          // ascending: 4, 5, 6, 7, 8, 9
 } else {
     (end..=start).rev().collect()    // descending: 9, 8, 7, 6, 5, 4
 }
}
The bonus `range_step` function in the code shows how to generate ranges with arbitrary step sizes using `.map(|i| start + i * step).take_while(|&x| x <= end)` โ€” the iterator equivalent of Python's `range(start, end, step)`.

What This Unlocks

Key Differences

ConceptOCamlRust
Built-in range`List.init n (fun i -> start + i)``(start..=end).collect()`
Inclusive rangeManual: `start..end+1` in `List.init``..=` is inclusive on both ends
DescendingRequires `List.rev` or negative step`(end..=start).rev().collect()`
Lazy evaluationEvaluated eagerly in list form`Range` is lazy; `.collect()` forces it
Step sizeCustom recursive function`.map()` + `.take_while()` chain
// Range โ€” 99 Problems #22
// Create a list containing all integers in a given range.
// range 4 9 โ†’ [4, 5, 6, 7, 8, 9]

fn range(start: i64, end: i64) -> Vec<i64> {
    if start <= end {
        (start..=end).collect()
    } else {
        (end..=start).rev().collect()
    }
}

/// Recursive version.
fn range_rec(start: i64, end: i64) -> Vec<i64> {
    if start > end {
        vec![]
    } else {
        let mut result = vec![start];
        result.extend(range_rec(start + 1, end));
        result
    }
}

/// Using Iterator::step_by for arbitrary step (generalized).
fn range_step(start: i64, end: i64, step: i64) -> Vec<i64> {
    let step = if step == 0 { 1 } else { step.abs() };
    if start <= end {
        (0..)
            .map(|i| start + i * step)
            .take_while(|&x| x <= end)
            .collect()
    } else {
        (0..)
            .map(|i| start - i * step)
            .take_while(|&x| x >= end)
            .collect()
    }
}

fn main() {
    println!("range(4, 9):      {:?}", range(4, 9));
    println!("range(9, 4):      {:?}", range(9, 4));
    println!("range(5, 5):      {:?}", range(5, 5));
    println!("range(-3, 3):     {:?}", range(-3, 3));
    println!("range_rec(1, 5):  {:?}", range_rec(1, 5));
    println!("step(0, 10, 2):   {:?}", range_step(0, 10, 2));
}

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

    #[test]
    fn test_range_ascending() {
        assert_eq!(range(4, 9), vec![4, 5, 6, 7, 8, 9]);
    }

    #[test]
    fn test_range_descending() {
        assert_eq!(range(9, 4), vec![9, 8, 7, 6, 5, 4]);
    }

    #[test]
    fn test_range_single() {
        assert_eq!(range(5, 5), vec![5]);
    }

    #[test]
    fn test_range_rec_matches() {
        assert_eq!(range(1, 5), range_rec(1, 5));
    }

    #[test]
    fn test_range_negative() {
        assert_eq!(range(-3, 0), vec![-3, -2, -1, 0]);
    }
}
(* Range *)
(* OCaml 99 Problems #22 *)

(* Implementation for example 22 *)

(* Tests *)
let () =
  (* Add tests *)
  print_endline "โœ“ OCaml tests passed"