Gleam Anonymous Functions
An anonymous function is a function without a name. You define it inline wherever a function value is needed — in a variable, as an argument to another function, or as a return value. Anonymous functions keep related logic close to where it is used.
Syntax
fn(parameters) { body }
Anonymous Function Anatomy
──────────────────────────────────────────────────
fn(x: Int) -> Int { x * 2 }
│ └──────────┘ └──────┘
│ parameters body
└── fn keyword (no name)
Storing in a Variable
let double = fn(x: Int) { x * 2 }
let greet = fn(name: String) { "Hello, " <> name }
double(5) // 10
greet("Ravi") // "Hello, Ravi"
Passing Inline to Higher-Order Functions
import gleam/list
let numbers = [1, 2, 3, 4, 5]
let squares = list.map(numbers, fn(n) { n * n })
// [1, 4, 9, 16, 25]
let odds = list.filter(numbers, fn(n) { n % 2 != 0 })
// [1, 3, 5]
let sum = list.fold(numbers, 0, fn(acc, n) { acc + n })
// 15
Inline Function Visual
──────────────────────────────────────────────────
list.map([1,2,3,4,5], fn(n) { n * n })
└─────────────┘
defined right here,
used right here
Type Inference
Gleam infers parameter and return types from context. You rarely need type annotations inside anonymous functions:
// Gleam knows n is Int because the list contains Int values
let doubled = list.map([10, 20, 30], fn(n) { n * 2 })
// Explicit types when inference needs help:
let parse = fn(s: String) -> Result(Int, Nil) { int.parse(s) }
Capturing Outer Variables (Closures)
An anonymous function can use variables from the scope where it was defined. This is called a closure:
let threshold = 60
let passing = list.filter([45, 72, 58, 88], fn(score) {
score >= threshold // threshold from outer scope
})
// [72, 88]
Closure Diagram
──────────────────────────────────────────────────
Outer scope: threshold = 60
fn(score) { score >= threshold }
│
└── "captures" threshold = 60
from the surrounding scope
Multi-Statement Anonymous Functions
The body of an anonymous function can contain multiple let bindings:
let process = fn(price: Float, tax_rate: Float) {
let tax = price *. tax_rate
let total = price +. tax
total
}
process(1000.0, 0.18) // 1180.0
Returning Anonymous Functions
pub fn make_multiplier(factor: Int) -> fn(Int) -> Int {
fn(n) { n * factor } // captures `factor` from outer scope
}
let triple = make_multiplier(3)
let times7 = make_multiplier(7)
triple(10) // 30
times7(10) // 70
The Capture Shorthand
Gleam provides a shorthand for simple single-argument anonymous functions using _ as a placeholder:
import gleam/int
// These two are equivalent:
list.map([1,2,3], fn(n) { int.to_string(n) })
list.map([1,2,3], int.to_string) // function reference
// For partially applied operations, use fn:
list.map([1,2,3], fn(n) { n + 10 })
Named vs Anonymous Functions
When to Use Each
──────────────────────────────────────────────────
Use named function when:
✓ The logic is reused in multiple places
✓ The function is complex (more than 2-3 lines)
✓ You want to test the function directly
✓ The function needs a descriptive name for clarity
Use anonymous function when:
✓ The logic is used in exactly one place
✓ The function is short (1-2 expressions)
✓ Defining it inline makes the call site clearer
✓ As a callback passed to map/filter/fold
Practical Example — Data Pipeline
import gleam/list
import gleam/string
import gleam/io
pub fn process_names(raw: List(String)) -> List(String) {
raw
|> list.map(fn(s) { string.trim(s) })
|> list.filter(fn(s) { string.length(s) > 0 })
|> list.map(fn(s) { string.uppercase(string.slice(s, 0, 1))
<> string.slice(s, 1, string.length(s) - 1) })
|> list.sort(string.compare)
}
pub fn main() {
let names = [" alice", "BOB", " carol ", "", "dave"]
let result = process_names(names)
io.debug(result)
// ["Alice", "Bob", "Carol", "Dave"]
}
Pipeline Steps
──────────────────────────────────────────────────
[" alice", "BOB", " carol ", "", "dave"]
↓ trim each
["alice", "BOB", "carol", "", "dave"]
↓ remove empty strings
["alice", "BOB", "carol", "dave"]
↓ capitalize first letter
["Alice", "BOB", "Carol", "Dave"] ← BOB stays — slice logic
↓ sort alphabetically
["Alice", "BOB", "Carol", "Dave"]
Key Points
Anonymous Functions Summary
──────────────────────────────────────────────────
1. Syntax: fn(params) { body }
2. Store in a variable: let f = fn(x) { x + 1 }
3. Pass directly: list.map(items, fn(x) { x * 2 })
4. Closures capture outer variables
5. Multi-line bodies use let bindings inside
6. Return type is the last expression
7. Gleam infers types from context in most cases
Anonymous functions remove the need to name every small piece of logic. When a function exists only to serve one specific call, define it right there — close to where it is used, easy to read, and impossible to accidentally reuse in the wrong context.
