Gleam Option Type
The Option type represents a value that may or may not exist. It replaces null entirely. Instead of returning nothing and hoping the caller checks for it, a function that might find nothing returns Option(a) — and the compiler forces every caller to handle both outcomes.
The Definition of Option
type Option(a) {
Some(a)
None
}
Option Diagram
──────────────────────────────────────────────────
Option(Int) can be:
┌──────────────┐ OR ┌──────────────┐
│ Some(42) │ │ None │
│ value: 42 │ │ (nothing) │
└──────────────┘ └──────────────┘
Some(value) wraps a present value. None signals absence. Both are valid Option values — neither causes a crash.
Creating Option Values
import gleam/option.{None, Some}
let found: Option(String) = Some("hello")
let missing: Option(String) = None
let score: Option(Int) = Some(95)
let no_score: Option(Int) = None
Functions That Return Option
Standard library functions return Option when a value might not exist:
import gleam/list
import gleam/map
let nums = [10, 20, 30]
let first = list.first(nums) // Some(10)
let empty = list.first([]) // None
let m = map.from_list([#("key", "val")])
let found = map.get(m, "key") // Ok("val") ← map uses Result
let missing = map.get(m, "other") // Error(Nil)
Extracting the Value — Pattern Matching
Always use case to unwrap an Option:
import gleam/list
let items = [5, 8, 2]
let result = list.first(items)
let message = case result {
Some(n) -> "First item: " <> int.to_string(n)
None -> "The list is empty"
}
// "First item: 5"
Pattern Match Flow
──────────────────────────────────────────────────
list.first([5, 8, 2]) → Some(5)
case Some(5) {
Some(n) → matches! n = 5 → "First item: 5"
None → skipped
}
option.map — Transform the Inner Value
Apply a function to the value inside Some, while leaving None untouched:
import gleam/option
let score: Option(Int) = Some(80)
let doubled = option.map(score, fn(n) { n * 2 })
// Some(160)
let nothing: Option(Int) = None
let still_nothing = option.map(nothing, fn(n) { n * 2 })
// None — no crash, just passes through
option.map Diagram
──────────────────────────────────────────────────
Some(80) ──map(×2)──▶ Some(160)
None ──map(×2)──▶ None
option.unwrap — Extract with a Default
Provide a fallback value when None occurs:
import gleam/option
let found: Option(Int) = Some(42)
let val = option.unwrap(found, 0) // 42
let missing: Option(Int) = None
let default = option.unwrap(missing, 0) // 0
option.then — Chaining Option Operations
Chain operations that each return Option, short-circuiting on the first None:
import gleam/option
import gleam/list
import gleam/map
let users = map.from_list([#(1, "Meera"), #(2, "Kiran")])
let posts = map.from_list([#("Meera", ["Post A", "Post B"])])
pub fn get_user_posts(user_id: Int) -> Option(List(String)) {
map.get(users, user_id)
|> option.from_result // convert Result to Option
|> option.then(fn(name) {
map.get(posts, name)
|> option.from_result
})
}
// get_user_posts(1) → Some(["Post A", "Post B"])
// get_user_posts(99) → None (user not found)
option.then Chain
──────────────────────────────────────────────────
user_id = 1
lookup user → Some("Meera")
│
└── lookup posts → Some(["Post A", "Post B"])
↓
Final: Some([...])
user_id = 99
lookup user → None
│
└── short-circuits → None (no further lookup)
Converting Between Option and Result
import gleam/option
let opt: Option(Int) = Some(5)
let res: Result(Int, Nil) = option.to_result(opt, Nil)
// Ok(5)
let res2: Result(Int, String) = Error("not found")
let opt2: Option(Int) = option.from_result(res2)
// None
Practical Example — User Lookup
import gleam/map
import gleam/option
import gleam/io
type User {
User(id: Int, name: String, age: Int)
}
const users = [
#(1, User(id: 1, name: "Divya", age: 25)),
#(2, User(id: 2, name: "Rahul", age: 30))
]
pub fn find_user(id: Int) -> Option(User) {
let db = map.from_list(users)
map.get(db, id) |> option.from_result
}
pub fn greet_user(id: Int) -> String {
case find_user(id) {
Some(user) -> "Welcome back, " <> user.name <> "!"
None -> "User not found."
}
}
pub fn main() {
io.println(greet_user(1)) // Welcome back, Divya!
io.println(greet_user(9)) // User not found.
}
Key Points
Option Essentials
──────────────────────────────────────────────────
1. Option(a) has two variants: Some(a) and None
2. Replaces null — no null pointer exceptions
3. Always handle both Some and None with case
4. option.map transforms the inner value safely
5. option.unwrap extracts with a fallback default
6. option.then chains optional operations
7. Convert to/from Result with to_result/from_result
The Option type makes absence explicit and safe. Every function that might not find a value says so in its return type — and the compiler refuses to let you ignore that possibility. This one type eliminates an entire category of crashes that plague null-based languages.
