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/

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 of
    bits 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)

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
init <PROJECT_NAME>
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


Created: 2024-09-18

Updated: 2024-11-16

Back