๐Ÿฆ€ Functional Rust
๐ŸŽฌ Error Handling in Rust Option, Result, the ? operator, and combinators.
๐Ÿ“ Text version (for readers / accessibility)

โ€ข Option represents a value that may or may not exist โ€” Some(value) or None

โ€ข Result represents success (Ok) or failure (Err) โ€” no exceptions needed

โ€ข The ? operator propagates errors up the call stack concisely

โ€ข Combinators like .map(), .and_then(), .unwrap_or() chain fallible operations

โ€ข The compiler forces you to handle every error case โ€” no silent failures

018: Slice List

Difficulty: 1 Level: Foundations Extract a subrange from a list using 1-based inclusive indices โ€” like `lst[i-1:k]` in Python.

The Problem This Solves

You have a list of items and need to extract a specific window: records 3 through 7, characters 2 through 5, rows 10 through 20. The task: given `['a','b','c','d','e','f','g','h','i','k']` and indices `3..7`, produce `['c','d','e','f','g']`. In Python you'd write `lst[2:7]` (0-based, exclusive end). In most textbooks and many APIs, indices are 1-based and inclusive โ€” which requires a mental translation every time. The off-by-one error is one of the most common bugs in slice operations. Rust makes this translation explicit in one place and safe everywhere else. You convert once (`i - 1` for 0-based start, `k.min(len)` for bounded end), then use the native slice syntax which the compiler verifies is in-bounds.

The Intuition

In Python: `lst[i-1:k]` (0-based, exclusive end) In JavaScript: `lst.slice(i-1, k)` This example uses 1-based inclusive indexing (like the OCaml 99 Problems source). So "slice from 3 to 7" means "include elements at positions 3, 4, 5, 6, 7" โ€” which in 0-based terms is indices 2 through 6. Rust's native slice syntax is 0-based and exclusive at the end: `lst[2..7]`. The function does the conversion for you. After that, `.to_vec()` copies the subrange into a new owned vector.

How It Works in Rust

fn slice<T: Clone>(lst: &[T], i: usize, k: usize) -> Vec<T> {
 let start = if i == 0 { 0 } else { i - 1 };  // 1-based โ†’ 0-based
 let end = k.min(lst.len());                    // clamp to list length
 if start >= end {
     return vec![];  // empty range
 }
 lst[start..end].to_vec()  // Rust slice: 0-based, exclusive end
}
The recursive version (`slice_rec`) walks the list with a position counter, collecting elements when `pos >= i && pos <= k`. It's slower (O(n) allocations) but shows how the index bookkeeping maps to explicit counting.

What This Unlocks

Key Differences

ConceptOCamlRust
Slice syntaxNo native slice; use `List.filteri``lst[start..end]` (0-based, exclusive)
Index convention1-based (99 Problems style)0-based natively; convert at boundary
Bounds safetyRuntime `Invalid_argument``.min(lst.len())` + safe slice
Copy to owned`List.map Fun.id``.to_vec()`
Empty rangeReturns `[]`Returns `vec![]`
// Slice List โ€” 99 Problems #18
// Extract a slice from a list given 1-based inclusive indices [i..k].
// slice ['a','b','c','d','e','f','g','h','i','k'] 3 7
//   โ†’ ['c','d','e','f','g']

fn slice<T: Clone>(lst: &[T], i: usize, k: usize) -> Vec<T> {
    // Convert 1-based to 0-based, inclusive on both ends
    let start = if i == 0 { 0 } else { i - 1 };
    let end = k.min(lst.len());
    if start >= end {
        return vec![];
    }
    lst[start..end].to_vec()
}

/// Recursive version.
fn slice_rec<T: Clone>(lst: &[T], i: usize, k: usize) -> Vec<T> {
    fn aux<T: Clone>(lst: &[T], i: usize, k: usize, pos: usize) -> Vec<T> {
        match lst {
            [] => vec![],
            [head, tail @ ..] => {
                if pos > k {
                    vec![]
                } else if pos >= i {
                    let mut result = vec![head.clone()];
                    result.extend(aux(tail, i, k, pos + 1));
                    result
                } else {
                    aux(tail, i, k, pos + 1)
                }
            }
        }
    }
    aux(lst, i, k, 1)
}

fn main() {
    let input = vec!['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k'];
    println!("Input:          {:?}", input);
    println!("Slice [3..7]:   {:?}", slice(&input, 3, 7));
    println!("Slice [1..3]:   {:?}", slice(&input, 1, 3));
    println!("Slice [1..1]:   {:?}", slice(&input, 1, 1));
    println!("Rec [3..7]:     {:?}", slice_rec(&input, 3, 7));
}

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

    #[test]
    fn test_slice_middle() {
        let input = vec!['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k'];
        assert_eq!(slice(&input, 3, 7), vec!['c', 'd', 'e', 'f', 'g']);
    }

    #[test]
    fn test_slice_from_start() {
        let input = vec![1, 2, 3, 4, 5];
        assert_eq!(slice(&input, 1, 3), vec![1, 2, 3]);
    }

    #[test]
    fn test_slice_single() {
        let input = vec!['a', 'b', 'c'];
        assert_eq!(slice(&input, 2, 2), vec!['b']);
    }

    #[test]
    fn test_slice_rec_matches() {
        let input = vec!['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k'];
        assert_eq!(slice(&input, 3, 7), slice_rec(&input, 3, 7));
    }
}
(* Slice List *)
(* OCaml 99 Problems #18 *)

(* Implementation for example 18 *)

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