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.

Leave a Comment

Your email address will not be published. Required fields are marked *