Introduction to Gleam, a New Functional Programming Language
Gleam is a type safe functional programming language for building scalable concurrent systems. Is it as friendly as it claims? We find out.
Jun 22nd, 2024 4:00am by
Image via Unsplash+.
import gleam/io
pub fn main() {
io.println("hello world!")
}
> brew install gleam
Rather than saving time for the moment, the “hello world” style one-liner is already there as the default code in hello.gleam:
If I run the whole project:
Note that the two packages were only compiled on the first run.
Package Management
There are two .toml files (apparently Tom’s Own Markup Language. Don’t ask), which act as configuration. As they should be simple, we can have a quick peek. In the gleam.toml:
[dependencies]
gleam_stdlib = ">= 0.34.0 and < 2.0.0"
So let’s replace the code in hello.gleam with the code to print out environment variables on demand:
import argv
import envoy
import gleam/io
import gleam/result
pub fn main() {
case argv.load().arguments {
["get", name] -> get(name)
_ -> io.println("Usage: get <name>")
}
}
fn get(name: String) -> Nil {
let value = envoy.get(name) |> result.unwrap("")
io.println(format_pair(name, value))
}
fn format_pair(name: String, value: String) -> String {
name <> "=" <> value
}
main entry point, we have two functions. They use exactly the same format as we saw in Virgil. It turns out that type annotations are optional, but considered good practice. Now, we get a bit functional. The argv load does what you expect, and pulls in a list of hopefully exactly two strings — with the first string equal to “get”. This is used in a case statement.
As a quick aside, the Gleam case is a little more flexible than in most non-functional languages. Here we see a lists’ contents being compared:
let result = case x {
[] -> "Empty list"
[1] -> "List of just 1"
[4, ..] -> "List starting with 4"
[_, _] -> "List of 2 elements"
_ -> "Some other list"
}
_ represents a default, and the possible cases are exhaustively checked.
Going back to our environment variable reading code, if the pattern isn’t a list of two strings, then the helper text is spat out. Otherwise, it calls the get function.
We see the pipe function, which just helps to make long functional calls a little more readable from left to right.
let value = envoy.get(name) |> result.unwrap("")
let value = result.unwrap(envoy.get(name),"")
name <> "=" <> value
Gleam has no null, no implicit conversions, and no exceptions. So if it compiles, you are good. Also, there is no numerical operator overloading, so the code for adding integers is different to that for adding floats:
io.debug(1 + 1) //ints
io.debug(1.0 +. 1.5) //floats
Algebraic Data Types
Finally, we saw Algebraic Data Types (ADTs) used in Virgil, so I’m keen to see how the equivalent works in Gleam. In fact, we’ve already seen the use of thecase statement.
We get custom types, which we pattern match over. So we are part of the way there:
pub type Season {
Spring
Summer
Autumn
Winter
}
fn weather(season: Season) -> String {
case season {
Spring -> "Mild"
Summer -> "Hot"
Autumn -> "Windy"
Winter -> "Cold"
}
}
import gleam/io
pub type Travel {
Walk(hours: Int)
Cycle(hours: Int)
Drive(hours: Int, speed: Int)
}
pub fn main() {
let walking = Walk(1)
let cycling = Cycle(1)
let bus_trip = Drive(2, 50)
let trip = [walking, cycling, bus_trip]
io.debug(trip)
}
// [Walk(hours: 1), Cycle(hours: 1), Drive(hours: 2, speed: 50)]
I don’t think I can associate a method inside a type, but I can access the record values to get a similar result as we got in Virgil. I’ll leave this as an exercise for a more fluent user!
For someone like me who doesn’t work with functional code much, Gleam is very approachable and doesn’t immediately confront me with terminology like “currying” and other functional shocks. But it should be a good way to get you to appreciate the immutable advantages of programming if you are not already an advocate.
YOUTUBE.COM/THENEWSTACK
Tech moves fast, don't miss an episode. Subscribe to our YouTube
channel to stream all our podcasts, interviews, demos, and more.