Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Functions

Use fn to define a function. Gleam runs the body top to bottom and returns the final value. There’s no return keyword.

Functions are private unless marked pub. Type annotations help with clarity but aren’t required.

pub fn main() {
  greet("Alex")
}

fn greet(name: String) {
  let message = make_message(name)
  io.println(message)
}

fn make_message(name: String) -> String {
  "Welcome, " <> name <> "!"
}

Higher-Order Functions

Functions can be passed around like any other value. You can use them to build flexible logic.

pub fn main() {
  let result = apply_twice(square, 3)
  io.println(int.to_string(result))
}

fn square(n: Int) -> Int {
  n * n
}

fn apply_twice(f: fn(Int) -> Int, x: Int) -> Int {
  f(f(x))
}

Anonymous Functions

You can define unnamed functions inline. These can also capture values from their environment.

pub fn main() {
  let double = fn(n) { n * 2 }
  let result = double_and_add(double, 5)
  io.println(int.to_string(result))

  let base = 10
  let add_base = fn(x) { x + base }
  io.println(int.to_string(add_base(5)))
}

fn double_and_add(f: fn(Int) -> Int, x: Int) -> Int {
  f(x) + x
}

Function Captures

Use _ to partially apply a function and create a new one.

pub fn main() {
  let greet = say("Hi", _)
  io.println(greet("Sam"))
}

fn say(prefix: String, name: String) -> String {
  prefix <> ", " <> name
}

This simplifies your code and makes pipelines easier to read.

Generic Functions

Generic functions work with any type, as long as it’s consistent within the call.

pub fn main() {
  io.println(duplicate("hey"))
  io.println(int.to_string(duplicate(42)))
}

fn duplicate(x: value) -> Tuple(value, value) {
  #(x, x)
}

The compiler ensures the types are used consistently and doesn’t allow mismatches.

Pipelines

The pipe operator passes the result of one expression into the next. It improves readability by following the data flow.

import gleam/string
import gleam/io

pub fn main() {
  "   Hello World!  "
  |> string.trim
  |> string.uppercase
  |> string.append("!!!")
  |> io.println
}

You can also use _ to place the piped value into another argument slot.

"42"
|> string.concat(["Value: ", _])
|> io.println

Labelled Arguments

Labels help show what each argument means. They’re useful when multiple arguments share a type.

pub fn main() {
  let total = compute_cost(units: 4, price_per_unit: 25)
  io.println(int.to_string(total))
}

fn compute_cost(units units: Int, price_per_unit cost: Int) -> Int {
  units * cost
}

Labels can be written in any order at the call site.

Label Shorthand

If your variable names match the parameter labels, you can use shorthand syntax.

pub fn main() {
  let width = 10
  let height = 5
  let unit = "cm"

  describe_rectangle(width:, height:, unit:)
}

fn describe_rectangle(
  width width: Int,
  height height: Int,
  unit unit: String,
) {
  let info = int.to_string(width) <> " x " <>
             int.to_string(height) <> " " <>
             unit

  io.println(info)
}

This keeps function calls compact and clear.