Gleam Functions
Functions are the building blocks of every Gleam program. A function groups related code under a name, accepts inputs, performs work, and returns a result. Well-written functions make programs readable, testable, and reusable.
Function Anatomy
Parts of a Gleam Function
──────────────────────────────────────────────────────────
pub fn add(a: Int, b: Int) -> Int {
│ │ └────────────┘ └─┘
│ │ parameters return type
│ └── function name
└── visibility (pub = public)
a + b ← function body (expression returned)
}
Every function consists of these parts: visibility keyword, fn keyword, name, parameters with types, return type, and body.
Writing a Simple Function
pub fn square(n: Int) -> Int {
n * n
}
The function body is the last expression — its value becomes the return value. Gleam does not use a return keyword. The result of the last expression is automatically returned.
Function Flow Diagram
──────────────────────────────────────────────────
square(5)
│
└── body: n * n
↓
5 * 5
↓
25 ← returned to caller
Calling Functions
import gleam/io
pub fn square(n: Int) -> Int {
n * n
}
pub fn main() {
let result = square(7)
io.debug(result) // 49
}
Call a function by writing its name followed by arguments in parentheses. The arguments must match the parameter types — Gleam verifies this at compile time.
Functions with Multiple Parameters
pub fn rectangle_area(width: Float, height: Float) -> Float {
width *. height
}
pub fn greet(name: String, language: String) -> String {
case language {
"Hindi" -> "नमस्ते, " <> name
"French" -> "Bonjour, " <> name
_ -> "Hello, " <> name
}
}
Labeled Arguments
Gleam supports labeled arguments. Labels make function calls self-documenting — you see exactly what each argument means at the call site.
pub fn send_email(to recipient: String, subject text: String) -> Nil {
// label: to parameter name: recipient
// label: subject parameter name: text
}
// Calling with labels:
send_email(to: "user@mail.com", subject: "Welcome")
Labeled vs Unlabeled
──────────────────────────────────────────────────
Without labels:
send_email("user@mail.com", "Welcome")
↑ Which is which? Not obvious.
With labels:
send_email(to: "user@mail.com", subject: "Welcome")
↑ Crystal clear.
Inside the function body, use the parameter name (not the label). Outside the function, callers use the label.
Ignoring Labels at the Call Site
If a label starts with an underscore, it is optional:
pub fn log(_level level: String, message: String) -> Nil {
// ...
}
// Call without label:
log("info", message: "Server started")Return Types
Every function declares what it returns after the -> arrow. This contract between the function and its callers is checked by the compiler.
Return Type Examples
──────────────────────────────────────────────────
pub fn get_name() -> String { "Gleam" }
pub fn get_count() -> Int { 42 }
pub fn is_valid() -> Bool { True }
pub fn process() -> Nil { io.println("done") }
pub fn get_items() -> List(String) { ["a", "b"] }
A function that produces no meaningful result returns Nil. Functions that could fail return Result or Option — covered in later topics.
Functions Are Values
In Gleam, functions are first-class values. You store them in variables, pass them to other functions, and return them from functions.
let double = fn(n: Int) -> Int { n * 2 }
let result = double(5) // 10This anonymous function (sometimes called a lambda) has no name. You assign it to the variable double and call it through that variable.
Passing Functions as Arguments
pub fn apply(value: Int, operation: fn(Int) -> Int) -> Int {
operation(value)
}
pub fn triple(n: Int) -> Int {
n * 3
}
pub fn main() {
let result = apply(4, triple)
io.debug(result) // 12
}
Higher-Order Function Diagram
──────────────────────────────────────────────────
apply(4, triple)
│
└── passes triple as the "operation"
│
└── triple(4) = 12
└── returned from apply
Private vs Public Functions
Visibility Rules
──────────────────────────────────────────────────
pub fn greet() -> String { ... }
→ Visible from other modules
→ Part of the module's public interface
fn helper() -> String { ... }
→ Visible only inside this file
→ Internal implementation detail
Use pub for functions that other modules need. Keep everything else private. This principle — exposing only what is necessary — is called encapsulation.
The Last Expression is the Return Value
Gleam returns the value of the last expression automatically. You cannot use return anywhere in the function body.
pub fn classify_score(score: Int) -> String {
let label = case score {
s if s >= 90 -> "Excellent"
s if s >= 70 -> "Good"
s if s >= 50 -> "Average"
_ -> "Below Average"
}
label // ← this is the return value
}
Functions Calling Other Functions
pub fn celsius_to_fahrenheit(c: Float) -> Float {
c *. 9.0 /. 5.0 +. 32.0
}
pub fn body_temp_status(temp_c: Float) -> String {
let temp_f = celsius_to_fahrenheit(temp_c)
case temp_f >= 100.4 {
True -> "Fever detected"
False -> "Normal temperature"
}
}
Call Chain Diagram
──────────────────────────────────────────────────
body_temp_status(38.5)
│
├── celsius_to_fahrenheit(38.5)
│ │
│ └── 38.5 × 9 / 5 + 32 = 101.3
│
└── 101.3 >= 100.4 → True → "Fever detected"
Recursive Functions
A function can call itself. This is called recursion. Gleam uses recursion where other languages use loops.
pub fn factorial(n: Int) -> Int {
case n {
0 -> 1
_ -> n * factorial(n - 1)
}
}
// factorial(5) = 5 × 4 × 3 × 2 × 1 = 120Practical Example — Bill Calculator
import gleam/io
import gleam/float
pub fn calculate_tip(bill: Float, percentage: Float) -> Float {
bill *. percentage /. 100.0
}
pub fn split_bill(total: Float, people: Int) -> Float {
total /. int.to_float(people)
}
pub fn final_bill(bill: Float, tip_percent: Float, people: Int) -> Float {
let tip = calculate_tip(bill, tip_percent)
let total = bill +. tip
split_bill(total, people)
}
pub fn main() {
let per_person = final_bill(1000.0, 10.0, 4)
io.debug(per_person) // 275.0
}
Bill Calculation Flow
──────────────────────────────────────────────────
bill = 1000.0, tip = 10%, people = 4
calculate_tip(1000.0, 10.0) = 100.0
total = 1000.0 + 100.0 = 1100.0
split_bill(1100.0, 4) = 275.0 per person
Key Rules for Gleam Functions
Summary
──────────────────────────────────────────────────
1. Define with fn keyword
2. All parameters must have type annotations
3. Return type follows the -> arrow
4. Last expression is the return value — no return keyword
5. pub makes a function visible outside the module
6. Functions are values — store and pass them freely
7. Labeled arguments make call sites readable
Functions in Gleam are pure by default — a function with the same inputs always produces the same output, with no hidden side effects. This predictability makes testing straightforward and debugging fast.
