The Result Type
Error Handling with Result
Gleam has no exceptions. Instead, functions that can fail return a Result type:
pub type Result(value, error) {
Ok(value)
Error(error)
}
A Result is either Ok with a success value, or Error with an error value.
Returning Results
fn divide(a: Int, b: Int) -> Result(Int, String) {
case b {
0 -> Error("division by zero")
_ -> Ok(a / b)
}
}
Handling Results
Use case to handle both outcomes:
case divide(10, 3) {
Ok(value) -> io.println("Result: " <> int.to_string(value))
Error(msg) -> io.println("Error: " <> msg)
}
The Result Module
The gleam/result module provides functions for working with results:
import gleam/result
// Transform the Ok value
result.map(Ok(5), fn(x) { x * 2 }) // Ok(10)
result.map(Error("oops"), fn(x) { x * 2 }) // Error("oops")
// Chain operations that return Results
result.try(Ok(5), fn(x) { Ok(x * 2) }) // Ok(10)
result.try(Error("oops"), fn(x) { Ok(x * 2) }) // Error("oops")
// Provide a default value
result.unwrap(Ok(5), 0) // 5
result.unwrap(Error("oops"), 0) // 0
Chaining with result.try
result.try is key for chaining operations. If any step returns Error, the chain short-circuits:
fn process() -> Result(Int, String) {
result.try(parse_int("42"), fn(x) {
result.try(divide(x, 2), fn(y) {
Ok(y + 1)
})
})
}
This nesting can get deep, which is why Gleam provides the use expression (next lesson).
Your Task
Write a function called safe_divide that takes two integers and returns Result(Int, String). It should return Error("division by zero") when the divisor is 0, otherwise Ok with the result.
Write a function called try_divide_and_add that divides a by b, then adds c to the result using result.map. Print the results for (10, 2, 3) and (10, 0, 3).