046 — Result Map
Tutorial Video
Text description (accessibility)
This video demonstrates the "046 — Result Map" functional Rust example. Difficulty level: Intermediate. Key concepts covered: Functional Programming. `Result::map` transforms the success value inside `Ok` while leaving `Err` unchanged — the functor operation for `Result`. Key difference from OCaml: 1. **`map_err` naming**: Rust: `map_err`. OCaml: `Result.map_error`. The same operation — transforms the `Err`/`Error` branch.
Tutorial
The Problem
Result::map transforms the success value inside Ok while leaving Err unchanged — the functor operation for Result. It is the equivalent of Option::map but for the two-channel success/failure type. Together with map_err, it enables transformation of both channels: map for the success value, map_err for the error value.
This pattern is essential for adapting between different result types in a pipeline. A library returns Result<i32, LibError>; your code needs Result<String, AppError>. Use result.map(|n| n.to_string()).map_err(AppError::from_lib) to adapt both sides without unwrapping.
🎯 Learning Outcomes
result.map(|v| transform(v)) to transform the Ok valueresult.map_err(|e| convert(e)) to transform the Err valuemap calls for sequential transformations on the success pathmap to add context: result.map(|v| (v, metadata))map is equivalent to and_then(|v| Ok(transform(v)))Result::map(f) to transform Ok(x) to Ok(f(x)) while passing Err(e) through unchangedResult::map_err(g) to transform the error value — apply when converting between error typesCode Example
#![allow(clippy::all)]
// Placeholder — pending conversionKey Differences
map_err naming**: Rust: map_err. OCaml: Result.map_error. The same operation — transforms the Err/Error branch.result.map(f) consumes the result by value. Use result.as_ref().map(f) to map over Result<&T, &E> without consuming. OCaml's GC handles this transparently.map_err call to change error types; OCaml's structural typing can sometimes infer error type changes without explicit conversion.map vs and_then**: map cannot fail — the function returns U, not Result<U, E>. If the transformation can fail, use and_then instead.Result::map only transforms Ok:** Errors pass through unchanged. result.map(f) applies f only if result is Ok(v) — otherwise returns the Err(e) unchanged. This is the Functor instance for Result.map_err for error transformation:** result.map_err(f) applies f to the error value — the mirror of map. Useful for converting between error types.Result.map:** Result.map f result applies f to Ok values. Result.map_error f result transforms the error. Both are OCaml 4.08+ standard library functions..map().map_err() can be chained to transform both success and error paths without nested match expressions.OCaml Approach
OCaml's Result.map f r: let map f = function Ok x -> Ok (f x) | Error e -> Error e. Result.map_error f r maps the error. Pipe style: parse_int s |> Result.map (fun n -> n * 2) |> Result.map string_of_int. OCaml 4.08+ provides Result.map and Result.map_error. Earlier: use pattern matching or define them yourself.
Full Source
#![allow(clippy::all)]
// Placeholder — pending conversionDeep Comparison
OCaml vs Rust: Result Map
Overview
See the example.rs and example.ml files for detailed implementations.
Key Differences
| Aspect | OCaml | Rust |
|---|---|---|
| Type system | Hindley-Milner | Ownership + traits |
| Memory | GC | Zero-cost abstractions |
| Mutability | Explicit ref | mut keyword |
| Error handling | Option/Result | Result<T, E> |
See README.md for detailed comparison.
Exercises
transform(r: Result<i32, String>) -> Result<String, String> that doubles the int and converts to string on success, and prepends "Error: " to error messages. Use both map and map_err.Result<&str, IoError>, write a chain that trims whitespace, parses as float, multiplies by 100, and rounds to int. Each step uses map.Vec<Result<i32, String>>, use partition to split into (Vec<i32>, Vec<String>) of successes and errors. This is the partition_result pattern.bimap<T, U, E, F>(f: impl Fn(T) -> U, g: impl Fn(E) -> F, result: Result<T, E>) -> Result<U, F> — transform both the success and error simultaneously.result_apply<T, U, E: Clone>(f: Result<impl Fn(T) -> U, E>, arg: Result<T, E>) -> Result<U, E> — the applicative <*> for Result.