Gleam
wiki | https://en.wikipedia.org/wiki/Gleam_(programming_language) |
home | https://gleam.run/ |
search | https://gloogle.run/ |
docs | https://gleam.run/documentation/ |
tutorial | https://tour.gleam.run/everything/ |
- by Loius Pilfold
- 2016
- gc
- statically typed, immutable objects, pattern matching, first class functions
- no pure, exceptions, macros, type classes, early returns
- compiles to Erlang and JS
- stdlib prefers
Result
overOption
- packages in hex.pm
- Releases (monthly minor releases)
- 03/24 1.0
- 09/24 1.5
Language
panic // program will crash panic as "wut!?" // program will crash with msg todo // program will crash todo as "Don't look!" // program will crash with msg
style
//// to document a module /// to document what is below (types,functions) fn a_function_name(a: Int) -> Int {} Constructor type AType = Int // type alias
- variable_name
- Constructor
variables
pub const answer: Int = 42 // top level constant, can be exported, must be literal values let size = 50_000 // immutable, shadowable let y = x * { x + 10 } // braces/blocks used to group expressions let assert [head,..] = items // program will crash if items==[]
types
type alias
type UserId = Int
Primitives
Int | 1_000 0x 0b 0o | + - |
Float | 7.0e7 | +. -. |
String | \u{123} "what" | <> |
Bool | True False | && ! ¦¦ |
Nil | Nil |
- Int
- no max limit on erlang
- are 64-bit float in javascript
- String
- UTF-8 binaries
- Nil
- a unit type
- used by functions that have nothing to return
- NOT a valid value of other type
Complex
list | [1,2] | List(t) | [hd,..tl] | list.head |
tuple | #("fo",2) | #(Int,String) | #(fst,snd) | foo.0 |
record | R(age: "fo") | R(n) | r.age | |
bitarray | BitArray | |||
dictionary | dict.from_list([#()]) | Dict(Int,Int) |
- dictionary are unordered
Custom Data Types
- Enum
- type Color { Red, Green, White }
- Record, aka custom data types
- type Person { Person(name: String), Anonymous }
- let p = Person(name: "Alice")
- p.name (has to exists on all varians and be on the same position/type)
- update syntax Person(..person, name: "Bob")
Result, gleam/result, aka a generic custom type
pub type Result(value, reason) { Ok(value) Error(reason) } use int_a_number <- try(parse_int("1")) // Ok(1) -> 1 use attempt_int <- try(parse_int("ouch")) // Error will be returned, code below won't run
Bit arrays
<<3>> <<3:size(8)-little>> <<"Hello, Joe!":utf8>>
- represents a sequence of 0's and 1's
options, they can be dash separated
size of segment in bits unit number of bits, size
is multiple ofbits nested bit array bytes nested bit array, byte-aligned float int of default size of 8 bits big Big Endian little Little Endian native Native Endianness utf8 encoded text (also _codepoint) utf16 encoded text (also _codepoint) utf32 encoded text (also _codepoint) signed unsigned
functions
pub fn sum(x: Int, y: Int) -> Int { // public x + y // implicit return }
- High order functions: can be passed as arguments or assined to variables
Anonymous functions
let mul = fn(x,y) { x * y } mul(1,2)
Function Capture
(shorthand for unary anonymous functions that pass its argument)let add_one_v1 = fn(x) { add(1,x) } let add_one_v2 = add(1,_)
Generic Functions (aka parametric polymorphism)
fn twice(argument: value, my_function: fn(value) -> value) -> value { my_function(my_function(argument)) }
Labelled Arguments
pub fn replace(inside string: String, each pattern: String, with replacement: String) {} pub fn replace(inside string , each pattern , with replacement) { go(string, patter, replacement) } replace(each: ",", with: " ", inside: "A,B,C")
deprecation
@deprecated("use new_fucntion instead") // attribute fn old_function() { Nil }
operators
- +, +.
- <>
= !
(structural equality, same for all types)- && ||
- N / 0 (div by 0 returns 0)
- |>
- a |> b(1,2)
- b(a,1,2)
- b(1,2)(a)
- a |> b(1,2)
use
- for using callbacks in an unindented style
before
result.try(get_username(), fn(username) { result.try(get_password(), fn(password) { result.map(log_in(username, password), fn(greeting){ greeting <> ", " <> username }) }) })
after
use username <- result.try(get_username()) use password <- result.try(get_password()) use greeting <- result.map(log_in(username, password)) greeting <> ", " <> username
externals
erlang + elixir
@external(erlang, "rand", "uniform") pub fn random_float() -> Float @external(erlang, "Elixir.IO", "inspect") pub fn inspect(a) -> a
erlang + javascript
pub type Datetime @external(erlang, "calendar", "local_time") @external(javascript, "./my_package_ffi.mjs", "now") // export function now() { return new Date(); } pub fn now() -> Datetime now()
gleam + erlang
@external(erlang, "lists", "reverse") pub fn reverse_list(items: List(e)) -> List(e) { tail_recursive_reverse(items, []) // gleam implementation }
control flow
- no loops, only recursion, has TCO
case
- there is no if/else
- has exhaustiveness checks
type User { LoggedIn(name: String, age: Int) Guest } let user = Guest case user,10 { // multiple subjects // [1,..] -> "list starts with 1" LoggedIn(name,..),_ -> name // spread to discard others "Tom" <> lastname,_ as usr -> "Hello " <> lastname <> " Tom..aka " <> usr // as Guest,10 | Guest,11 -> "Guest user 10-ish" // alternative pattern Guest,i if i > 20 -> "Guest user " <> int.to_string(i) // guard, CANNOT call functions Guest,_ -> "Guest user" }
modules (import/export)
public opaque type | pub opaque type PosI { PosI(inn: Int) } | constructors are NOT exported |
private fn | fn identity() | |
public fn | pub fn identity() | |
qualified | import mylibrary/mymod | src/mylibrary/mymod.gleam |
qualified | import gleam/io | io.println() |
as qualified | import gleam/string as ss | ss.reverse("abc") |
unqualified | import gleam/io.{println} | println() |
type unqualified | import gleam/string_builder.{type StringBuilder} | let t: StringBuilder = |
stdlib
gleam/ | public functions/types |
---|---|
bit_array | |
bool | to_string to_int |
bytes_builder | |
dict | new from_list insert delete |
dynamic | |
float | max ceiling |
function | |
int | max clamp random to_string |
io | println debug |
iterator | |
list | map filter fold find |
option | Option None Some |
order | |
pair | |
queue | |
regex | |
result | map try unwrap |
set | |
string | inspect, reverse, append |
string_builder | |
uri |
- result
- map: takes fn -> value (aka Functor?)
- try: takes fn -> Result() (aka Monad?)
- unwrap: extracts the Ok(success) value, or given default
Tools
gleam- | argument |
---|---|
add | <PACKAGE> |
add* | –dev lustre_dev_tools |
new | <PROJECT_NAME> |
run | |
run | -m lustre/dev add tailwind |
build | –target javascript |
build | –target erlang |
export | erlang-shipment |
- *needs inotify-tools for hotreload
gleam.toml
https://gleam.run/writing-gleam/gleam-toml/
field | eg value | description |
---|---|---|
name | "" | |
version | "1.1.0" | |
target | "javascript" | default to all targets |
description | "" | for Hex |
licenses | ["Apache-2.0"] | for Hex |
repository | {type="github",user="",repo=""} | for Hex |
links | [{title="",href=""}] | for Hex |
[dependencies] | ||
[dev-dependencies] |
/build
- /build/dev/javascript
- module_name/
- prelude.mjs
- gleam.mjs
- /build/dev/erlang
- gleam_stdlib
- module_name/ebin/*.beam
Codebases
- https://github.com/gleam-lang/example-echo-server
- https://github.com/gleam-lang/example-todomvc
- https://github.com/gleam-lang/packages
- https://github.com/gleam-lang/example-lisp-interpreter
- https://github.com/gleam-lang/developer-survey
- https://github.com/gleam-lang/cookbook?tab=readme-ov-file
- language-tour