Gleam for Erlang users

Variables

Erlang

In Erlang variables are written with a capital letter, and can only be assigned once.

Size = 50
Size2 = Size + 100
Size2 = 1 % Runtime error! Size2 is 150, not 1

Gleam

In Gleam variables are written with a lowercase letter, and names can be reassigned.

let size = 50
let size = size + 100
let size = 1 // size now refers to 1

Partial assignments

Erlang

In Erlang a partial pattern that does not match all possible values can be used to assert that a given term has a specific shape.

[Element] = SomeList % assert `SomeList` is a 1 element list

Gleam

In Gleam the assert keyword is used to make assertions using partial patterns.

let [element] = some_list // Compile error! Partial pattern
assert [element] = some_list

Variables type annotations

Erlang

In Erlang it's not possible to give type annotations to variables.

Gleam

In Gleam type annotations can optionally be given when binding variables.

let some_list: List(Int) = [1, 2, 3]

Gleam will check the type annotation to ensure that it matches the type of the assigned value.

Gleam does not need annotations to type check your code, but you may find it useful to annotate variables to hint to the compiler that you want a specific type to be inferred.

Comments

Erlang

In Erlang comments are written with a % prefix.

% Hello, Joe!

Gleam

In Gleam comments are written with a // prefix.

// Hello, Joe!

Comments starting with /// are used to document the following statement, comments starting with //// are used to document the current module.

//// This module is very important.

/// The answer to life, the universe, and everything.
const answer: Int = 42

Operators

OperatorErlangGleamNotes
Equal=:===In Gleam both values must be of the same type
Equal==
Not equal=/=!=In Gleam both values must be of the same type
Not equal/=
Greater than>>In Gleam both values must be ints
Greater than>>.In Gleam both values must be floats
Greater or equal>=>=In Gleam both values must be ints
Greater or equal>=>=.In Gleam both values must be floats
Less than<<In Gleam both values must be ints
Less than<<.In Gleam both values must be floats
Less or equal=<>=In Gleam both values must be ints
Less or equal=<>=.In Gleam both values must be floats
Boolean andandalso&&In Gleam both values must be bools
Boolean andand
Boolean ororelse⎮⎮In Gleam both values must be bools
Boolean oror
Add++In Gleam both values must be ints
Add++.In Gleam both values must be floats
Subtract--In Gleam both values must be ints
Subtract--.In Gleam both values must be floats
Multiply**In Gleam both values must be ints
Multiply**.In Gleam both values must be floats
Dividediv/In Gleam both values must be ints
Modulorem%In Gleam both values must be ints
Pipe⎮>See the pipe section for details

Constants

Erlang

In Erlang macros can be defined to name literals we may want to use in multiple places. They can only be used within the current module

-define(the_answer, 42).

main() ->
  ?the_answer.

Gleam

In Gleam constants can be used to achieve the same.

const the_answer = 42

fn main() {
  the_answer
}

Gleam constants can be referenced from other modules.

import other_module

fn main() {
  other_module.the_answer
}

Data types

Strings

All strings in Gleam are UTF-8 encoded binaries.

Erlang

<<"Hellø, world!"/utf8>>.

Gleam

"Hellø, world!"

Tuples

Tuples are very useful in Gleam as they're the only collection data type that allows for mixed types of elements in the collection. The syntax for a tuple literal - tuple("a", "b") - can be confused for a function call, which it is not!

Erlang

Tuple = {"username", "password", 10}.
{_, Password, _} = Tuple.

Gleam

let my_tuple = tuple("username", "password", 10)
let tuple(_, password, _) = my_tuple

Lists

Lists in Erlang are allowed to be of mixed types, but not in Gleam. They retain all of the same performance sematics.

The cons operator works the same way both for pattern matching and for appending elements to the head of a list, but it uses a different syntax.

Erlang

List0 = [2, 3, 4].
List1 = [1 | List0].
[1, SecondElement | _] = List1.
[1.0 | List1].

Gleam

let list = [2, 3, 4]
let list = [1, ..list]
let [1, second_element, ..] = list
[1.0, ..list] // Type error!

Atoms

In Erlang atoms can be created as needed, but in Gleam all atoms must be defined as values in a custom type before being used. Any value in a type definition in Gleam that does not have any arguments is an atom in Erlang.

There are some exceptions to that rule for atoms that are commonly used and have types built-in to Gleam that incorporate them, such as ok, error and booleans.

In general, atoms are not used much in Gleam, and are mostly used for boolens, ok and error result types, and defining custom types.

Erlang

Var = my_new_var.

{ok, true}.

{error, false}.

Gleam

type MyNewType {
  MyNewVar
}
let var = MyNewVar

Ok(True)

Error(False)

Maps

In Erlang, maps can have keys and values of any type, and they can be mixed in a given map. In Gleam, maps can have keys and values of any type, but all keys must be of the same type in a given map and all values must be of the same type in a given map.

There is no map literal syntax in Gleam, and you cannot pattern match on a map. Maps are generally not used much in Gleam. You're more often going to use custom types (which are analagous to Erlang Records) or lists of two element tuples (which are proplists or orddicts in Erlang).

Erlang

#{"key1" => "value1", "key2" => "value2"}.

#{["key1"] => "value1", "key2" => "value2"}.

Gleam

import gleam/map

map.from_list([tuple("key1", "value1"), tuple("key2", "value2")])

map.from_list([tuple(["key1"], "value1"), tuple("key2", "value2")]) \\ Type error!

Custom types

Records

In Erlang, Records are a specialized data type built on a tuple. Gleam does not have anything called a record, but custom types can be used in Gleam in much the same way that records are used in Erlang, even though custom types don't actually define a record in Erlang when it is compiled.

The important thing is that a custom type allows you to define a collection data type with a fixed number of named fields, and the values in those fields can be of differing types.

Erlang

-record(person, {age, name}).

Person = #person{name="name", age=35}.

Name = #Person.name.

Gleam

type Person {
  Person(age: Int, name: String)
}

let person = Person(name: "name", age: 35)

let name = person.name