generics

Generics: type parameters, Option and Result, and the list builtins.

Running it

What CI runs and the output it checks, byte for byte.

sh

dawn run examples/data/generics.dawn

tree total: 15
or_default(None, 7) = 7
hello
err: division by zero
len = 6
get(xs, 4) = 10
lists equal: true

examples/data/generics.dawn

generics.dawnOpen in playground
# Generics: type parameters, Option and Result, and the list builtins.
#
# Run: dawn run examples/data/generics.dawn

type Tree[T] =
  | Leaf
  | Node(left: Tree[T], value: T, right: Tree[T])

fn insert(t: Tree[Int], v: Int) -> Tree[Int] =
  match t {
    Leaf -> Node(Leaf, v, Leaf)
    Node(l, x, r) ->
      if v < x { Node(insert(l, v), x, r) }
      else { Node(l, x, insert(r, v)) }
  }

fn total(t: Tree[Int]) -> Int =
  match t {
    Leaf -> 0
    Node(l, v, r) -> total(l) + v + total(r)
  }

fn or_default[T](o: Option[T], d: T) -> T =
  match o {
    Some(v) -> v
    None -> d
  }

fn safe_div(a: Int, b: Int) -> Result[Int, String] =
  if b == 0 { Err("division by zero") } else { Ok(a / b) }

pub fn main() -> Unit !io = {
  # generic tree
  let e: Tree[Int] = Leaf
  let t = e.insert(5).insert(2).insert(8)
  println("tree total: ${total(t)}")

  # Option + inference across arguments
  println("or_default(None, 7) = ${or_default(None, 7)}")
  println(or_default(Some("hello"), "fallback"))

  # Result
  match safe_div(10, 0) {
    Ok(v) -> println("ok ${v}")
    Err(m) -> println("err: ${m}")
  }

  # lists
  let xs = range(1, 5) ++ [10, 20]
  println("len = ${len(xs)}")
  println("get(xs, 4) = ${xs.get(4).or_default(-1)}")
  println("lists equal: ${[1, 2] ++ [3] == [1, 2, 3]}")
}

test "the tree keeps everything that went in" {
  let e: Tree[Int] = Leaf
  let t = e.insert(5).insert(2).insert(8)
  assert total(t) == 15
}

test "one generic function serves every element type" {
  assert or_default(None, 7) == 7
  assert or_default(Some("hello"), "fallback") == "hello"
}

test "a failure is a value" {
  assert safe_div(10, 2) == Ok(5)
  assert safe_div(10, 0) == Err("division by zero")
}