A Subset of Gleam

The project's interpreter implements the subset of Gleam described on this page. Anything outside this subset is reported as an error instead of being evaluated.

The draw Function

Every drawing defines

fn draw(shape_slider: Int) -> List(Path) {
  ...
}

The shape_slider parameter is a whole number in [0, 100] taken from the shape slider in the app, and the returned list of paths is what the animator draws. A drawing may also define other top-level functions.

Values

The interpreter has integers, booleans, lists, functions, and the types that describe a drawing:

type Point {
  Point(x: Int, y: Int)
}

type Shape {
  Line(start: Point, end: Point)
}

type Path {
  Path(shape: Shape, start: Int, end: Int, thickness: Int)
}

A Path names the Shape to draw, the start and end times between which it is drawn (in tenths of a second), and a line thickness. A Point is a position on the canvas: (0, 0) is the center, x and y run from -500 to 500, and positive y is down. The thickness uses the same units, so a line looks thicker on a larger canvas.

Built-in Functions

  • random(min: Int, max: Int) -> Int — a random Int in [min, max).
  • abs(n: Int) -> Int — the absolute value of n.
  • The constructors of the record types above: Point, Line, and Path. These are the only functions that accept labelled arguments, such as Point(x: 0, y: 1).
  • Some gleam/list functions: list.map, list.filter, list.append, list.length, and list.flatten. They take the same arguments and behave the same way as in gleam/list, but no import is needed.

Language Features

  • Functions — the draw function, top-level helper functions, and anonymous functions defined within the body of other functions (e.g., fn(x) { x * 2 }). As in Gleam, a function's parameters must have distinct names, as must the top-level functions and the variables in one pattern (discards such as _ can repeat).

  • Function calls — the call's target is any expression that evaluates to a function: a built-in (random, list.map), a user-defined helper, a let-bound function, or another call's result (e.g., f(x)(y)).

  • Integers including literals (e.g. 4096), arithmetic operators (+, -, *, /, %) and comparison operators (<, >, <=, >=, ==, !=). As in Gleam, / truncates toward zero, % is the remainder (with the sign of the left operand, so -7 % 3 is -1), and both yield 0 when dividing by zero.

  • Booleans including True, False, and the operators && and ||. As in Gleam, each one only evaluates its right side if it's needed, so in False && f(x), f is not called. == and != compare any two values, not just integers.

  • Dot expressions — For example, p.x and p.y for the coordinates of a Point p.

  • Variables bound by pattern arms in case expressions.

  • let bindings — let name = expr binds the result of expr to name for use in the rest of the block.

  • case expressions to branch on a Bool or Int value or to destructure a List.

  • Integer patterns — For example, 0 -> ... matches only the integer 0.

  • List patterns — For example, [a, b] (exactly two elements), [a] (exactly one), [a, b, ..rest] (two or more, binding rest to a list of the others), [a, b, ..] (two or more, ignoring the others), and [_, next, ..] (ignore the first, bind the second).

  • The wildcard _ to discard values in patterns.

  • List prepending — [a, b, ..rest] as an expression builds a new list by prepending elements to an existing list rest (the expression form of the .. rest pattern, allowed only at the end of a list literal).

  • Function captures — add(1, _) as shorthand for fn(x) { add(1, x) }.

  • The pipe operator — x |> f(a) passes x as the first argument of the call, i.e. f(x, a), and x |> f calls f with x as its only argument. Pipes chain, so paths |> list.filter(keep) |> list.map(thicken) reads as a left-to-right pipeline.

  • use bindings — use x <- f(a) calls f with one extra final argument: an anonymous function whose parameter is x and whose body is the rest of the block. So

    use p <- list.map(points)
    Point(p.x, p.y + 10)
    

    is shorthand for list.map(points, fn(p) { Point(p.x, p.y + 10) }). Multiple names (use a, b <- f) become multiple parameters, and a use cannot be the last line of a block, since the rest of the block is the function's body.

What Is Not Included

Other Gleam features are not available, such as string or float literals, tuples, and custom type definitions. Adding some of them is one possible extension of the project.

Evaluation is also bounded, so that a drawing cannot hang the browser: a program that recurses too deeply, does too much work in total (no matter how that work is spread across recursive branches), or builds a list that grows too long stops with an error rather than running forever or crashing the app.


Back to Top

Accessibility Nondiscrimination

Copyright ©2026, Regents of the University of California and respective authors.

This site is built following the Berkeley Class Site template, which is generously based on the Just the Class, and Just the Docs templates.

View all course offerings