Gleam notes
11 December, 2020
Meta
This document should be accessible at https://jmnorlund.net/posts/2020-12-11-gleam.
Introduction
Gleam is a language which runs on Erlang/OTP, it is is statically typed and compiled to Erlang.
Running code
use rebar3 shell
, if you want to recompile from within the shell you can use r3:do(compile).
Adding and running new files
Say you add a file to src/app called foo.gleam which contains a function bar
, you can reference it in the shell via app@foo:bar().
Running tests
rebar3 eunit
Syntax
Functions
Labelled arguments
pub fn replace(
in string: String,
each pattern: String,
with replacement: String,
) {
// The variables `string`, `pattern`, and `replacement` are in scope here
}
replace(in: "A,B,C", each: ",", with: " ")
Anonymous functions
pub fn run() {
let add = fn(x, y) { x + y }
add(1, 2)
}
Function capturing
pub fn add(x: Int , y: Int ) -> Int {
x + y
}
pub fn run() {
// This is the same as add(add(add(1, 3), 6), 9)
1
|> add(_, 3)
|> add(_, 6)
|> add(_, 9)
}
Pipe operator
pub fn add_one(x) {
x + 1
}
pub fn three() {
1
|> add_one
|> add_one // 3
}
Data Structures
pub type Person {
Person(
name: String,
gender: Option(String),
shoe_size: Int,
age: Int,
is_happy: Bool,
)
}
pub fn have_birthday(person) {
// It's this person's birthday, so increment their age and
// make them happy
Person(..person, age: person.age + 1, is_happy: true)
}
Types
Constants
const
const hello: String = "Hello"
pub const start_year = 2101
pub const end_year = 2111
pub describe(year: Int) -> String {
case year {
year if year < start_year -> "Before"
year if year > end_year -> "After"
_ -> "During"
}
}
Strings
There is no string concatenation operator in Gleam, instead you use the function string.concat
which takes a list of strings and returns a concatenated string.
import gleam/string
string.concat(["foo","bar"]) // "foobar"
Conditionals
There is no if/else in Gleam, the only flow control mechanism in Gleam is case expressions.
Case expressions and guards
Code examples
How would you write this piece of Haskell if you were to write it in Gleam?
Foo n | n == 0 = doThis | n == 1 = doThat | n == 2 = doAnother | (n >= 3 ) && (n <= 99) = doDefault
NobbZ Idag 09:35 Untested, as I currently don't do active gleam:
case n { 0 -> doThis 1 -> doThat 2 -> doAnother n if 3 <= n && n <= 99 -> doDefault }
Guards & limitations of guards in Gleam, compared to Haskell
lpil: one difference between guards in Gleam and in Haskell is that in Gleam only a subset of expressions are permitted there, while Haskell permits any expression. The Gleam ones run in constant time and get optimised by the Erlang compiler. It’s a virtual machine limitation
jmn Idag 10:25 so I can't do:
pub fn test_one(x) { x > 100 } pub fn test_two(x) { x < 100 } pub fn guard_function_case(n) -> String { case n { n if test_one(n) -> "Larger than hundred." n if test_two(n) -> "Smaller than hundred." _ -> "One hundred" } }
or can I?
lpil Idag 10:26 Functions cannot be called in guards as they might diverge Though those function bodies could be used instead As the int comparison operators are permitted
Example code
import gleam/string
pub fn hello_world() -> String {
"Hello, from gthree!"
}
pub fn hi(hi: String) -> String{
string.concat(["hi, ", hi])
}
Type checking example:
pub fn moo() -> String {
hi(1)
}
results in:
error: Type mismatch
┌─ /home/jmn/git/gthree/src/gthree.gleam:12:6
│
12 │ hi(1)
│ ^
Expected type:
String
Found type:
Int
↑