4. Modeling data: ADTs and records

An algebraic data type (ADT) lists its constructors with |. Add derive Show to make it printable:

type Shape =
  | Circle(r: Float)
  | Rect(w: Float, h: Float)
  derive Show

fn area(s: Shape) -> Float =
  match s {
    Circle(r) -> 3.14159 * r * r
    Rect(w, h) -> w * h
  }

pub fn main() -> Unit !io = {
  println(to_string(Circle(2.0)))
  println(to_string(area(Rect(3.0, 4.0))))
}
Open in playground
Circle(2.0)
12.0

A record is a product type with named fields, constructed and updated with braces:

type Point = { x: Float, y: Float } derive Show

fn shift(p: Point, dx: Float) -> Point =
  Point { ..p, x: p.x + dx }

pub fn main() -> Unit !io = {
  let a = Point { x: 1.0, y: 2.0 }
  println(to_string(shift(a, 10.0)))
}
Open in playground
Point { x: 11.0, y: 2.0 }

What type declares is always a new type; to give an existing one an alias, use alias — the two spellings are interchangeable, and it is mostly used to give a tuple or a function type a name you can say out loud:

alias Point = (Int, Int)

fn shift(p: Point, dx: Int) -> Point = {
  let (x, y) = p
  (x + dx, y)
}

pub fn main() -> Unit !io = {
  let p: Point = (1, 2)
  println(to_string(shift(p, 3)))
}
Open in playground
(4, 2)