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.

Leave a Comment

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