
Overview
Gleam is "a friendly language for building type-safe systems that scale!" It runs on BEAM (Björn’s Erlang Abstract Machine) which is the Erlang virtual machine that is also used by Elixir. Gleam programs can be compiled to Erlang or JavaScript.
Gleam was created by Louis Pilford who currently resides in London.
Gleam has a syntax that is inspired by Elm, Go, Lua, OCaml, and Rust. Like OCaml, Gleam has strong type inference, using the Hindley Milner type system, making it unnecessary to specify types.
Gleam includes a compiler (implemented in Rust), build tool, package manager, code formatter, language server, standard library, JavaScript bindings, and a WASM API. It was released in 2024.
Gleam programs can use libraries implemented in Gleam, Elixir, and Erlang.
The Gleam logo is a pink starfish named Lucy that glows underwater.
Resources
Installing
To install in macOS, enter brew update
and brew install gleam
. Installing gleam
also installs erlang
.
To see the currently installed version, enter gleam --version
.
To upgrade to the latest version in macOS, enter brew upgrade gleam
.
For other platforms, see Installing Gleam.
VS Code
To edit Gleam code using VS Code, consider installing the extension Gleam by Gleam.
Code formatting will not be performed on save by default. To configure it, open the Command Palette, select Format Document, and choose "Gleam". After doing this one time, code will be formatted on save.
Projects
Gleam tooling for working with projects is inspired by the Rust cargo
tool.
To create a new Gleam project, enter gleam new {name}
. Project names can only contain lowercase letters, digits, and underscores. Names beginning with "gleam_" are reserved.
This creates the following files:
.github/workflows/test.yml
This runs all the tests in a GitHub Action every time changes are pushed.
.gitignore
README.md
gleam.toml
src/{name}.gleam
test/{name}_test.gleam
Gleam source files have the .gleam
file extension.
To format all the .gleam
files in the project from the command-line rather than in an editor like VS Code, enter gleam format
. The code formatter automatically sorts import
statements.
To build the project, enter gleam build
.
To build and run the project, enter gleam run
.
This compiles the project into Erlang files (.erl
extension) that can be found in the build/dev/erlang/{name}/_gleam_artefacts
directory. It then runs the main
function in the .gleam
file within the src
directory identified by the name
property in the gleam.toml
file. It will output a log of all the steps it takes, and finally "Hello from {name}!".
To compile to JavaScript instead of Erlang, add the --target
(or -t
) option with the value javascript
(default is erlang
). For example, gleam run -t javascript
. This compiles the project into JavaScript files (.mjs
extension for JavaScript modules) that can be found in the build/dev/javascript/{name}
directory. It will output a log of all the steps it takes, and finally produce the same output as when using Erlang.
To run all the tests, enter gleam test
.
This will output a log of all the steps it takes, and finally "1 tests, 0 failures".
To delete all the generated files, enter gleam clean
. This deletes the build
directory.
Watch Mode
It's desirable to have something watch the files in project for changes and automatically run the main module again or run all the tests again when a change is detected. Gleam does not currently support this, but an issue has been created for it.
Modules
Each .gleam
source file defines a module that contains definitions for items like functions, types, and so on.
To use the items in a module, import it with the import
keyword.
To run the main
function in a module other than the main module of a project, specify it with the --module
or -m
option. For example, gleam run -m other
runs the main
function in the file src/other.gleam
.
The Gleam standard library provides the following modules:
gleam/bit_array
gleam/bool
gleam/bytes_builder
gleam/dict
gleam/dynamic
gleam/float
gleam/function
gleam/int
gleam/io
gleam/iterator
gleam/list
gleam/option
gleam/order
gleam/pair
gleam/queue
gleam/regex
check
- returns aBool
indicating if aString
matches aRegex
compile
- creates aRegex
from aString
and a set ofOptions
from_string
- creates aRegex
from aString
and noOptions
scan
- returns aList
of all theRegex
matches found in aString
split
- returns aList
of substrings created by splitting aString
on delimiters that match aRegex
gleam/result
gleam/set
gleam/string
gleam/string_builder
gleam/uri
Dependencies
To add a dependency, enter gleam add {name1} {name2} ...
This updates the gleam.toml
file and installs the packages in the build/packages
directory.
The build
directory can be deleted. It will be recreated automatically when gleam run
or gleam test
are executed. All packages listed as "dependencies" or "dev-dependencies" in the gleam.toml
file will be re-installed.
Importing Packages
To import a package in a Gleam source file:
import {name}
Some packages have subpackages. To import a subpackage:
import {name}/{sub-name}
The line import gleam/io
makes the module name io
available as a prefix that can be used to access all the functions it defines. For example, io.println("Hello, World!")
.
A module can be given an alternate name with the as
keyword. This can be used to prevent name conflicts. For example, import gleam/string as text
.
Module functions can be imported to enable using them without a module name qualifier. For example, import gleam/io.{debug, println}
. followed by println("Hello, World!")
.
The as
keyword can also be used to assign alternate names to imported functions. For example:
import gleam/int.{square_root as sqrt}
The Gleam community discourages the use of function calls that are not qualified by their module name.
Comments
Gleam supports three kinds line comments.
//
is for regular comments///
is for documenting types and functions////
is for documenting modules at the top of their source files
End of line comments are not supported. When these comments are placed at the end of a source line, the code formatter will move them to the next line.
There is no multiline comment syntax.
Naming Rules
The names of functions and variables must start with a lowercase letter and can only contain lowercase letters, digits, and underscores.
The names of types and type constructors must start with an uppercase letter and can only contain letters and digits.
Functions
Functions are defined with the fn
keyword. They can be named or anonymous.
TODO: Add more detail on functions.
Type Inference
Gleam infers the types of all variables, function parameters, and function return types. Types can be specified for documentation purposes, but they must match the inferred types.
The Gleam language server, used by VS Code Gleam extension, enables hovering over a variable, function defintion, or function call to display their inferred types in a popup.
For example:
// No types specified.
fn add(a, b) {
a + b
}
// Types specified.
fn subtract(a: Int, b: Int) -> Int {
a - b
}
Just like OCaml, Gleam supports different operators for integer and floating point values.
Custom Types
The type
keyword is used to define a custom type.
Variables
Variables are declared with the let
keyword. All variables and function parameters are immutable.
Math
Gleam is currently missing lots of math constants and functions found of most other programming languages. See this issue.
Control Flow
The only control flow mechanism in Gleam is the case
expression. For simple cases this can be a bit verbose because the code formatter will cause every case
expression to be at least four lines.
For example, the following JavaScript:
if (a < b) console.log('yes');
let color = score > 5 ? 'green' : 'red';
could be written as follows in Gleam:
case a < b {
True -> io.println("yes")
False -> Nil
}
let color = case score {
score if score > 5 -> "green"
_ -> "red"
}
TODO: Add more examples of case expressions including pattern matching and guards.
Error Handling
Many Gleam functions return a Result type which holds either an Ok
or an Error
value. There are several ways to handle this that are demonstrated below. Note that the square_root
function produces an error when passed a negative number.
import gleam/float
import gleam/int
import gleam/io.{debug, println}
import gleam/result
pub fn main() {
// All case branches must have the same result type.
// Here all case braches have a Float result.
case int.square_root(25) {
Ok(result) -> result
Error(_) -> 0.0
}
|> debug
// Here all case braches have a String result.
case int.square_root(25) {
Ok(r) -> float.to_string(r)
Error(_) -> "No real root"
}
|> debug
// assert causes a crash the function after = results in an Error.
let assert Ok(result) = int.square_root(25)
debug(result)
// result.unwrap takes a value of type Result and
// returns its OK value or the supplied value on Error.
-25
|> int.square_root
|> result.unwrap(0.0)
// returns supplied value on Error
|> debug
}
Currying
Unlike OCaml, Gleam does not provide automatic function currying. Calling a function with fewer arguments than it has parameters results in an error rather than returning a new function that expects the remaining arguments.
A "function capture" creates a new single argument function from an existing one by calling it with a single "hole". Using an underscore for one of the arguments specifies the hole. For example:
import gleam/function
import gleam/io
fn add(a, b) {
a + b
}
pub fn main() {
let plus5 = add(5, _)
debug(plus5(2)) // 7
}
The gleam/function
module defines the functions curry2
through curry6
where the number indicates the number of parameters in a function passed to it. A new function is returned that is curried, meaning it takes a single argument and returns another function that takes a single argument, repeatedly until all arguments are supported. For example:
import gleam/function
import gleam/io
fn add2(a, b) {
a + b
}
fn add3(a, b, c) {
a + b + c
}
pub fn main() {
// The type of plus10 is fn(Int) -> Int.
let plus10 = function.curry2(add2)(10)
debug(plus10(9)) // 19
// The type of curried_add3 is fn(Int) -> fn(Int) -> fn(Int) -> Int.
let curried_add3 = function.curry3(add3)
debug(curried_add3(1)(2)(3)) // 6
}
Packages
Gleam Packages is the official Gleam package repository. For example, the "mist" web server package can be found here.
Web Development
Gleam web development is supported by many libraries including gleam_http, lustre, mist, wisp, ...