Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-mcp

Model Context Protocol server for Pudu language documentation and compiler tools

0.1.1Apache-2.01

InstallClose

Docs.pudu

Pudu61 lines184.5 KB

GitHub ↗
1/** @Generated.Docs.Corpus — published Pudu prose, generated; do not edit */2module PuduLangMcp.Generated.Docs34import PuduLangMcp.Domain.Docs.Chapter as Chapter56export const REVISION: Str = "c5609a87"78export const CHAPTERS: Array[Chapter.Chapter] = [9  Chapter.Chapter{group: "docs", slug: "introduction", title: "Introduction", markdown: "# Introduction\n\nPudu is a statically typed programming language for programs that are easy to read, safe to change, and honest about failure. What a function takes, what it gives back, whether it can fail, and whether it changes what it was given are all written in its signature, so a reader can tell what code promises without reading its body.\n\n> Pudu is pre-release (0.1.0). Programs run on an interpreter, dependencies are local directories, and the language and its standard library may still change before a stable release.\n\n## What Pudu looks like\n\n```pudu\nmodule Hello\n\nimport Std.Io as Io\n\nfn main() -> Int \{\n  let _written = Io.writeLine(\"Hello from Pudu!\")\n  0\n\}\n```\n\nEvery file names its module, imports what it uses, and declares what it exports. A program starts at `main`, and the whole number `main` returns is the program's exit status.\n\n## Install\n\nNo binary release has been published yet. Pudu builds from source with GHC 9.10 or later and Cabal 3.12 or later:\n\n```sh\ngit clone https://github.com/chrismichaelps/pudu-lang.git\ncd pudu-lang\ncabal install exe:pudu --installdir=\"$HOME/.local/bin\" --overwrite-policy=always\npudu version\n```\n\nThe installed `pudu` carries its standard library, so nothing else needs to be installed beside it. macOS and Linux x86-64 are tested; Windows is not.\n\n## Run your first program\n\nSave the program above as `Hello.pudu` and run it:\n\n```sh\npudu run Hello.pudu\n```\n\nTo start a project with its own manifest, source directory, and tests:\n\n```sh\npudu init hello\ncd hello\npudu run src/Main.pudu\npudu test\n```\n\n## What Pudu is built around\n\n- **Failure is a value.** A function that can fail returns `Result[T, E]`, and the caller decides what happens. There are no exceptions.\n- **Absence is a value.** `Option[T]` holds `Some(value)` or `None`. Ordinary types never hold `null`.\n- **Change is visible.** `let` never changes, `var` may, and `&mut T` marks the one place allowed to change a borrowed value.\n- **Patterns are checked.** A `match` must cover every shape a value can have.\n- **Imports are explicit.** There are no wildcard imports, so every name's origin is in the import list.\n\n## How this documentation is organised\n\nThe chapters are written to be read in order, each building on the ones before it:\n\n1. **Starting out** — [getting started](/docs/getting-started), [basics](/docs/basics), [functions](/docs/functions), [types](/docs/types), and [numbers](/docs/numbers).\n2. **Working with data** — [text](/docs/text), [collections](/docs/collections), [control flow](/docs/control-flow), and [errors](/docs/errors).\n3. **Structuring programs** — [ownership](/docs/ownership), [modules and packages](/docs/modules), [dependencies](/docs/dependencies), [traits](/docs/traits), [generics](/docs/generics), and [compile time and macros](/docs/compile-time).\n4. **Building real software** — [testing](/docs/testing), [files and the system](/docs/files), [data formats](/docs/data-formats), [HTTP](/docs/http), [concurrency](/docs/concurrency), and [unsafe and foreign code](/docs/foreign-code).\n5. **Reference** — the [standard library](/docs/standard-library) map and [tooling](/docs/tooling).\n\nEvery example is a complete program. Copy one into a file named after its module, run it with `pudu run`, and change it to see what happens. If you already know what you are looking for, the [API reference](/modules) lists everything a program can import.\n"},10  Chapter.Chapter{group: "docs", slug: "getting-started", title: "Getting started", markdown: "# Getting started\n\nThis chapter takes you from an installed compiler to a project with its own modules and tests. By the end you will have run a program, changed it, split it into modules, and checked it with a test suite.\n\n## Check the installation\n\nPudu is one command. Once it is on your path, ask it for its version:\n\n```sh\npudu version\n```\n\nIf the command is not found, build and install it as the [introduction](/docs/introduction#install) describes, and make sure `$HOME/.local/bin` is on your `PATH`.\n\n## A single file\n\nThe smallest Pudu program is one file. Save this as `Hello.pudu`:\n\n```pudu\nmodule Hello\n\nimport Std.Io as Io\n\nfn main() -> Int \{\n  let _written = Io.writeLine(\"Hello from Pudu!\")\n  0\n\}\n```\n\nRun it:\n\n```sh\npudu run Hello.pudu\n```\n\nThree things are worth noticing already:\n\n- The file's first line names its module, and the name must match the file name: `module Hello` lives in `Hello.pudu`.\n- Nothing is available until it is imported. `Io.writeLine` works because of `import Std.Io as Io`.\n- `main` returns a whole number, and that number becomes the program's exit status. `0` means success.\n\nWriting a line can fail — the output may be closed — so `Io.writeLine` returns a `Result`. Binding it to a name that starts with `_` says, visibly, that the program received the result and chose not to act on it. The [errors](/docs/errors) chapter shows how to act on it instead.\n\n## Checking without running\n\n`pudu check` compiles a file and reports every problem without running anything. It is the fastest way to find out whether a change is correct:\n\n```sh\npudu check Hello.pudu\n```\n\nA mistake is reported with a code, the place it happened, and a suggestion. Change `Io.writeLine` to `Io.writeLne` and check again: the compiler answers with `E3033`, points at the name, and says what the module does export.\n\n## Start a project\n\nA project keeps its source, its tests, and a manifest together. `pudu init` creates one:\n\n```sh\npudu init hello\ncd hello\n```\n\nIt writes these files:\n\n| Path | Holds |\n| --- | --- |\n| `pudu.toml` | the manifest: the package name, its version, the language versions it supports, and where its source lives |\n| `src/Main.pudu` | the program's entry point |\n| `src/App/Greeting.pudu` | an application module, which `Main` imports |\n| `src/Domain/Greeting.pudu` | a domain module, with the logic the application uses |\n| `test/App/GreetingTest.pudu` | a test suite for both |\n| `README.md`, `.gitignore` | the usual project companions |\n\nRun the program and its tests:\n\n```sh\npudu run src/Main.pudu\npudu test\n```\n\nThe first prints `Hello, world.` and the second reports `2 assertions held`.\n\n## How the modules fit together\n\nA module's name is its path under `src`. `src/Domain/Greeting.pudu` is `module Domain.Greeting`, and another module reaches it with `import Domain.Greeting as Greeting`.\n\nThe generated domain module holds one exported function:\n\n```pudu\nmodule Greeting\n\n/// A greeting for somebody, or for the world when nobody was named.\nexport fn forName(name: Str) -> Str \{\n  if name.isEmpty() \{ \"Hello, world.\" \} else \{ \"Hello, \" + name + \".\" \}\n\}\n\nfn main() -> Int \{\n  if forName(\"\") == \"Hello, world.\" && forName(\"Ada\") == \"Hello, Ada.\" \{ 0 \} else \{ 1 \}\n\}\n```\n\n`export` makes `forName` visible to other modules; everything else stays private. A comment that starts with `///` documents the declaration below it, and editors show it when you hover over a use.\n\n## Make a change\n\nOpen `src/Domain/Greeting.pudu` and add a second function beside `forName`:\n\n```pudu\nmodule Farewell\n\nexport fn farewell(name: Str) -> Str \{\n  if name.isEmpty() \{ \"Goodbye.\" \} else \{ \"Goodbye, \{name\}.\" \}\n\}\n\nfn main() -> Int \{\n  if farewell(\"Grace\") == \"Goodbye, Grace.\" \{ 0 \} else \{ 1 \}\n\}\n```\n\n`\"Goodbye, \{name\}.\"` is text with a value placed inside it; the [text](/docs/text) chapter covers it in full. Then add a check for the new function to `test/App/GreetingTest.pudu`, inside the list the suite already has:\n\n```pudu\nmodule FarewellTest\n\nimport Std.Test as Test\n\nfn farewell(name: Str) -> Str \{\n  if name.isEmpty() \{ \"Goodbye.\" \} else \{ \"Goodbye, \{name\}.\" \}\n\}\n\nexport fn main() -> Int \{\n  let checks = Test.suite(\"farewell\", &[\n      Test.equals(\"names somebody\", &farewell(\"Grace\"), &\"Goodbye, Grace.\"),\n      Test.equals(\"says goodbye to nobody in particular\", &farewell(\"\"), &\"Goodbye.\")\n    ])\n  Test.report(&Test.run(&checks))\n\}\n```\n\nRun `pudu test` again. A failing check prints what it expected and what it found.\n\n## Reading the command line\n\nA program reads its arguments through `Std.Env`. `Env.at(0)` is the first argument after the program's name, and it is an `Option` because it may not have been given:\n\n```pudu\nmodule Greet\n\nimport Std.Env as Env\nimport Std.Io as Io\nimport Std.Option as Option\n\nexport fn main() -> Int \{\n  let name = Option.unwrapOr(Env.at(0), \"world\")\n  match Io.writeLine(\"Hello, \{name\}!\") \{\n    case Ok(_) => 0\n    case Err(_) => 1\n  \}\n\}\n```\n\n## The everyday loop\n\n| While you are | Run |\n| --- | --- |\n| writing | `pudu check src/Main.pudu` |\n| trying it | `pudu run src/Main.pudu`, or `pudu run --watch src/Main.pudu` to rerun on every save |\n| verifying | `pudu test` |\n| tidying | `pudu fmt src test` |\n\nEvery command is described in [tooling](/docs/tooling). The next chapter, [basics](/docs/basics), looks closely at what a file is made of.\n"},11  Chapter.Chapter{group: "docs", slug: "basics", title: "Basics", markdown: "# Basics\n\nThis page covers what every Pudu file is made of: a module, its imports, and the values and functions it declares.\n\n## Modules\n\nEvery file begins with exactly one `module` declaration, and the name matches the file's path. `module Shapes.Area` lives in `Shapes/Area.pudu`. A file holds declarations only; nothing runs when a module is loaded.\n\n```pudu\nmodule Greeting\n\nimport Std.Io as Io\n\nconst GREETING: Str = \"Hello\"\n\nexport fn greet(name: Str) -> Str \{\n  \"\{GREETING\}, \{name\}!\"\n\}\n\nfn main() -> Int \{\n  let _written = Io.writeLine(greet(\"Pudu\"))\n  0\n\}\n```\n\n## Imports\n\nImports are absolute, and there are exactly three forms:\n\n| Form | What it binds |\n| --- | --- |\n| `import Std.Text` | the module, used as `Std.Text.trim(value)` |\n| `import Std.Text as Text` | the module under a shorter name, `Text.trim(value)` |\n| `import Std.Option \{unwrapOr\}` | the named items, used unqualified |\n\nThere are no wildcard imports. A reader can always answer \"where did this name come from\" from the import list alone.\n\n## Visibility\n\nDeclarations are private to their module unless they are marked `export`. Exported functions must write out every parameter type and their return type, because other modules depend on that signature.\n\n## Values\n\n| Keyword | Meaning |\n| --- | --- |\n| `let` | an immutable binding |\n| `var` | a binding that may be assigned again |\n| `const` | a value computed while the program is compiled |\n\n```pudu\nmodule Values\n\nfn main() -> Int \{\n  let language = \"Pudu\"\n  var lessons = 1\n  lessons = lessons + 1\n  let summary = \"\{language\} has \{lessons\} lessons\"\n  if summary.isEmpty() \{ 1 \} else \{ 0 \}\n\}\n```\n\nAt module scope only `const` is allowed, so a program has no global mutable state. A `const` initialiser runs at compile time and cannot read files, the clock, or anything else outside the program.\n\n## Taking a value apart\n\nA binding can name the parts of a value instead of the value itself. A record is taken apart by\nfield, a tuple and an array by position, and `..` in an array pattern holds whatever the named\nelements did not take:\n\n```pudu\nmodule Apart\n\ntype Point = \{ x: Int, y: Int \}\n\nfn main() -> Int \{\n  let point = Point\{x: 3, y: 4\}\n  let \{x, y\} = point\n  let \{x: across\} = point\n\n  let pair = (10, 20)\n  let (left, right) = pair\n\n  let scores = [95, 82, 47, 61]\n  let [best, second, ..rest] = scores\n  let [..earlier, worst] = scores\n\n  var \{y: movable\} = point\n  movable = movable + 1\n\n  if x == 3 && y == 4 && across == 3\n    && left == 10 && right == 20\n    && best == 95 && second == 82 && rest == [47, 61]\n    && earlier.length() == 3 && worst == 61\n    && movable == 5\n  \{\n    0\n  \} else \{\n    1\n  \}\n\}\n```\n\n`var` binds parts that may be assigned again. A pattern here has to be one that always applies: one\nthat tests a tag, like `Some(value)`, has nowhere to go when it does not match, so it belongs in\n`let … else` instead. An array pattern is the exception — it names a length, and an array of another\nlength stops the program where the binding is.\n\n## Functions\n\nA function names its parameters and their types, and writes its result type after `->`. The body is a block whose last expression is the result, or an expression after `=`:\n\n```pudu\nmodule Arithmetic\n\nfn double(number: Int) -> Int = number * 2\n\nfn describe(number: Int) -> Str \{\n  let doubled = double(number)\n  \"\{number\} doubled is \{doubled\}\"\n\}\n\nfn main() -> Int \{\n  if describe(21) == \"21 doubled is 42\" \{ 0 \} else \{ 1 \}\n\}\n```\n\nGeneric functions take type parameters in square brackets:\n\n```pudu\nmodule Generics\n\nfn first[T](items: &Array[T]) -> Option[T] \{\n  if items.length() == 0 \{ None \} else \{ Some(items[0]) \}\n\}\n\nfn main() -> Int \{\n  match first(&[3, 1, 2]) \{\n    case Some(value) => value - 3\n    case None => 1\n  \}\n\}\n```\n\n## Text\n\nStrings are UTF-8. An expression in braces inside a string is interpolated, and `\\\{` or `\\\}` writes a literal brace:\n\n```pudu\nmodule Text\n\nfn main() -> Int \{\n  let name = \"Ada\"\n  let line = \"Hello, \{name\}! There are \{name.length()\} letters.\"\n  let braces = \"\\\{ not interpolated \\\}\"\n  if line.contains(\"Ada\") && braces.startsWith(\"\\\{\") \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Comments\n\n- `//` starts a line comment, and `/* ... */` block comments nest.\n- `///` above a declaration is its documentation. `pudu doc` reads it, and editors show it on hover.\n\n## Statements and blocks\n\nA statement ends at the end of its line; there are no semicolons. Two statements written on one line are an error. A line continues the previous statement when that line ends with an operator waiting for its right side, or when the next line begins with `.` or `?`:\n\n```pudu\nmodule Lines\n\nfn main() -> Int \{\n  let total = 1 +\n    2 +\n    3\n  let shouted = \"quiet\"\n    .toUpper()\n  if total == 6 && shouted == \"QUIET\" \{ 0 \} else \{ 1 \}\n\}\n```\n\nA block's value is its last expression. `if` and `match` are expressions, so both can produce a value directly.\n"},12  Chapter.Chapter{group: "docs", slug: "functions", title: "Functions", markdown: "# Functions\n\nFunctions are where a Pudu program does its work. This chapter covers declaring them, calling them, giving parameters defaults, passing functions as values, and writing function literals.\n\n## Declaring a function\n\nA function names its parameters with their types and states what it returns:\n\n```pudu\nmodule Area\n\nfn rectangleArea(width: Int, height: Int) -> Int \{\n  width * height\n\}\n\nfn main() -> Int \{\n  if rectangleArea(3, 4) == 12 \{ 0 \} else \{ 1 \}\n\}\n```\n\nThe last expression in the body is the result, so there is no `return` in `rectangleArea`. A function that produces nothing useful returns `()`, the unit value, and may leave the return type out when it is not exported.\n\n## Expression bodies\n\nA function whose whole body is one expression can say so with `=`:\n\n```pudu\nmodule Doubling\n\nfn double(n: Int) -> Int = n * 2\n\nfn square(n: Int) -> Int = n * n\n\nfn main() -> Int \{\n  if double(square(3)) == 18 \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Returning early\n\n`return` leaves a function straight away with a value. It reads best at the top of a function, dealing with the special cases before the main work:\n\n```pudu\nmodule Grading\n\nfn grade(score: Int) -> Str \{\n  if score < 0 || score > 100 \{ return \"invalid\" \}\n  if score >= 90 \{ return \"excellent\" \}\n  \"scored \{score\}\"\n\}\n\nfn main() -> Int \{\n  let ok = grade(-5) == \"invalid\" && grade(95) == \"excellent\" && grade(70) == \"scored 70\"\n  if ok \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Default values\n\nA parameter can have a default, used when a call leaves the argument out. Parameters with defaults come after the ones without:\n\n```pudu\nmodule Defaults\n\nfn greet(name: Str, greeting: Str = \"Hello\", punctuation: Str = \"!\") -> Str \{\n  \"\{greeting\}, \{name\}\{punctuation\}\"\n\}\n\nfn main() -> Int \{\n  let plain = greet(\"Ada\")\n  let warm = greet(\"Ada\", \"Welcome\")\n  let quiet = greet(\"Ada\", \"Hi\", \".\")\n  if plain == \"Hello, Ada!\" && warm == \"Welcome, Ada!\" && quiet == \"Hi, Ada.\" \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Recursion\n\nA function may call itself. There is no special syntax, and the recursion ends when a branch stops calling:\n\n```pudu\nmodule Factorial\n\nfn factorial(n: Int) -> Int \{\n  if n <= 1 \{ 1 \} else \{ n * factorial(n - 1) \}\n\}\n\nfn fibonacci(n: Int) -> Int \{\n  if n < 2 \{ n \} else \{ fibonacci(n - 1) + fibonacci(n - 2) \}\n\}\n\nfn main() -> Int \{\n  if factorial(5) == 120 && fibonacci(10) == 55 \{ 0 \} else \{ 1 \}\n\}\n```\n\nFor long-running work, a loop is usually clearer and uses less memory than deep recursion; the [control flow](/docs/control-flow) chapter covers loops.\n\n## Functions are values\n\nA function can be stored in a binding, passed to another function, and kept in a collection. Its type is written `fn(ParameterTypes) -> Result`:\n\n```pudu\nmodule Values\n\nfn double(n: Int) -> Int = n * 2\n\nfn increment(n: Int) -> Int = n + 1\n\nfn applyTwice(change: fn(Int) -> Int, start: Int) -> Int \{\n  change(change(start))\n\}\n\nfn main() -> Int \{\n  let steps = [double, increment]\n  var value = 5\n  for step in steps \{\n    value = step(value)\n  \}\n  if applyTwice(double, 3) == 12 && value == 11 \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Function literals\n\nA function literal is a function written where it is used. The short form, with `=>`, has a single expression as its body; the long form has a block and states its return type:\n\n```pudu\nmodule Literals\n\nfn main() -> Int \{\n  let numbers = [1, 2, 3, 4, 5, 6]\n  let evens = numbers.filter(fn(n: Int) => n % 2 == 0)\n  let labels = evens.map(fn(n: Int) -> Str \{\n    let doubled = n * 2\n    \"\{n\} doubles to \{doubled\}\"\n  \})\n  if evens == [2, 4, 6] && labels[0] == \"2 doubles to 4\" \{ 0 \} else \{ 1 \}\n\}\n```\n\nA literal can use the bindings around it. It captures them by copying, so it sees their values as they were when it was written, and it cannot change them:\n\n```pudu\nmodule Capturing\n\nfn adder(amount: Int) -> fn(Int) -> Int \{\n  fn(n: Int) => n + amount\n\}\n\nfn main() -> Int \{\n  let addTen = adder(10)\n  let addOne = adder(1)\n  if addTen(5) == 15 && addOne(5) == 6 \{ 0 \} else \{ 1 \}\n\}\n```\n\n`adder` returns a function. Each call makes a new one that remembers its own `amount`.\n\n## The short form\n\nThe same literal is written with bars instead of `fn`, which is the form to reach for when the\nliteral is an argument and the interesting part is the body. The types are usually clear from where\nit is used, so they can be left off:\n\n```pudu\nmodule ShortLiterals\n\nfn twice(f: fn(Int) -> Int) -> fn(Int) -> Int \{ |x| f(f(x)) \}\n\nfn main() -> Int \{\n  let numbers = [1, 2, 3, 4, 5, 6]\n  let evens = numbers.filter(|n| n % 2 == 0)\n  let doubled = numbers.map(|n| n * 2)\n  let total = numbers.reduce(|carried, n| carried + n, 0)\n\n  let annotated = |n: Int| -> Int \{ n * 3 \}\n  let takesNothing = || 7\n  let block = |n| \{\n    let squared = n * n\n    squared + 1\n  \}\n\n  if evens == [2, 4, 6]\n    && doubled[0] == 2\n    && total == 21\n    && annotated(2) == 6\n    && takesNothing() == 7\n    && block(3) == 10\n    && twice(|n| n + 3)(1) == 7\n  \{\n    0\n  \} else \{\n    1\n  \}\n\}\n```\n\n`|x| body` and `fn(x) => body` build the same value; nothing can tell them apart afterwards. `||` is\nthe literal that takes nothing — the two bars written together. `async` goes in front of either form.\n\nBecause a bar is also the operator that joins two values, a literal that begins a line is read as a\nnew statement rather than as a continuation of the line above. That is what lets a literal be the\nlast expression of a block, which is where one most often goes:\n\n```pudu\nmodule LiteralResult\n\nfn chooser(step: Int) -> fn(Int) -> Int \{\n  let doubled = step * 2\n  |n| n + doubled\n\}\n\nfn main() -> Int \{\n  if chooser(5)(1) == 11 \{ 0 \} else \{ 1 \}\n\}\n```\n\nA literal holds on to the names it mentions, and only those. `doubled` above is kept because the\nliteral uses it; anything else in scope is free to be collected as soon as the function returns.\n\n## Generic functions\n\nA function can work for many types by naming a type parameter in square brackets. The compiler works out the type at each call:\n\n```pudu\nmodule Generic\n\nimport Std.Option as Option\n\nfn firstOr[T](items: &Array[T], fallback: T) -> T \{\n  if items.isEmpty() \{ fallback \} else \{ items[0] \}\n\}\n\nfn pairUp[A, B](left: A, right: B) -> (A, B) \{\n  (left, right)\n\}\n\nfn main() -> Int \{\n  let number = firstOr(&[7, 8, 9], 0)\n  let word = firstOr(&[], \"none\")\n  let pair = pairUp(\"age\", 36)\n  if number == 7 && word == \"none\" && pair[1] == 36 \{ 0 \} else \{ 1 \}\n\}\n```\n\nA type parameter can also require behaviour, such as `T: Ord` for values that can be compared. That is covered with [traits](/docs/traits).\n\n## Parameters that change what they are given\n\nA parameter normally receives a copy of a value or a read-only borrow of it. A parameter typed `&mut T` may change the caller's value, and the caller writes `&mut` to agree:\n\n```pudu\nmodule Changing\n\nfn addBonus(score: &mut Int, bonus: Int) -> () \{\n  *score = *score + bonus\n\}\n\nfn main() -> Int \{\n  var score = 40\n  addBonus(&mut score, 2)\n  if score == 42 \{ 0 \} else \{ 1 \}\n\}\n```\n\nThe [ownership](/docs/ownership) chapter explains borrowing in full.\n\n## Exported functions\n\nA function marked `export` can be imported by other modules. Its parameter types and return type must be written out, because other modules are checked against its signature alone.\n"},13  Chapter.Chapter{group: "docs", slug: "types", title: "Types", markdown: "# Types\n\nEvery value in Pudu has one type, known when the program is compiled. This page covers the built-in types, the types a program declares, and the collections the language provides.\n\n## Built-in types\n\n| Type | Values |\n| --- | --- |\n| `Int`, `UInt` | whole numbers the width of the target machine |\n| `Int8` … `Int128`, `UInt8` … `UInt128` | whole numbers of a fixed width |\n| `Float32`, `Float64` | floating-point numbers; `Float` is `Float64` |\n| `Decimal` | exact base-ten numbers, written `1.5d` |\n| `BigInt` | whole numbers of any size |\n| `Bool` | `true` and `false` |\n| `Char` | one Unicode scalar value, written `'a'` |\n| `Str` | UTF-8 text |\n| `()` | the unit value, for results that carry nothing |\n\nFixed-width arithmetic is checked: `+`, `-`, and `*` stop the program with a diagnostic naming the type rather than wrapping around. The wrapping operators `&+ &- &*` and the saturating operators `+| -| *|` are there when that is what you mean. A literal may carry its width, as in `255u8` or `1.5f32`. [Numbers](/docs/numbers) covers each of these in depth.\n\n## Records\n\nA record type names its fields. A record is built by naming the type and every field:\n\n```pudu\nmodule Records\n\ntype User = \{ id: Int, name: Str, email: Str \}\n\nfn main() -> Int \{\n  let ada = User\{id: 1, name: \"Ada\", email: \"ada@example.com\"\}\n  let renamed = User\{..ada, name: \"Ada Lovelace\"\}\n  if renamed.id == ada.id && renamed.name != ada.name \{ 0 \} else \{ 1 \}\n\}\n```\n\n`User\{..ada, name: n\}` builds a copy of `ada` with one field replaced, so changing one field never means writing out all the others. Fields are immutable unless the type marks them `mut`.\n\n## Sum types\n\nA sum type lists the shapes a value can take. Each variant may carry values:\n\n```pudu\nmodule Shapes\n\nimport Std.Io as Io\n\ntype Point = \{ x: Float64, y: Float64 \}\n\ntype Shape =\n  | Circle(Point, Float64)\n  | Rectangle(Point, Point)\n\nfn area(shape: &Shape) -> Float64 \{\n  match shape \{\n    case Circle(_, radius) => 3.14159 * radius * radius\n    case Rectangle(low, high) => (high.x - low.x) * (high.y - low.y)\n  \}\n\}\n\nfn main() -> Int \{\n  let origin = Point\{x: 0.0, y: 0.0\}\n  let shapes = [Circle(origin, 1.0), Rectangle(origin, Point\{x: 2.0, y: 3.0\})]\n  for shape in shapes \{\n    let _written = Io.writeLine(\"area: \{area(&shape)\}\")\n  \}\n  0\n\}\n```\n\nA variant can also name what it carries, written `Circle\{ radius: Float64 \}`. It is then built as `Circle\{radius: 2.0\}` and matched as `case Circle\{radius\}`.\n\n## Option and Result\n\nTwo sum types appear in almost every program:\n\n- `Option[T]` is `Some(value)` or `None`. It is how Pudu writes a value that may be absent; no ordinary type can hold `null`.\n- `Result[T, E]` is `Ok(value)` or `Err(problem)`. It is how Pudu writes work that may fail. See [Errors](/docs/errors).\n\nBecause they are ordinary sum types, their helpers are module functions rather than methods: `Option.unwrapOr(value, fallback)`, from `Std.Option`.\n\n## Generic types\n\nA type may take type parameters, in square brackets:\n\n```pudu\nmodule Boxes\n\ntype Pair[A, B] = \{ first: A, second: B \}\n\nfn swap[A, B](pair: Pair[A, B]) -> Pair[B, A] \{\n  Pair\{first: pair.second, second: pair.first\}\n\}\n\nfn main() -> Int \{\n  let swapped = swap(Pair\{first: 1, second: \"one\"\})\n  if swapped.first == \"one\" \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Tuples\n\nA tuple groups values of different types without naming them: `(1, \"one\")`. A member is read by its position, `pair[0]`. `()` is the empty tuple, the unit value.\n\n## Collections\n\n| Type | Built with | Notes |\n| --- | --- | --- |\n| `Array[T]` | `[1, 2, 3]` | an ordered sequence; `push`, `insert`, and `remove` return a new array |\n| `Map[K, V]` | `mapOf([(\"a\", 1)])` | keys kept in order |\n| `Set[T]` | `#\{1, 2, 3\}` or `setOf([1, 2, 3])` | members kept in order |\n\nArrays, maps, and sets never change in place: every operation answers a new value that shares what it can with the old one. Arrays carry built-in methods such as `length()`, `contains(x)`, `map(f)`, `filter(f)`, and `reduce(f, initial)`. Maps carry `get(key)`, `containsKey(key)`, `insert(key, value)`, `remove(key)`, `keys()`, and `size()`. `value in set` tests membership.\n\n```pudu\nmodule Collections\n\nfn main() -> Int \{\n  let numbers = [1, 2, 3, 4]\n  let evens = numbers.filter(fn(n: Int) => n % 2 == 0)\n  let ages = mapOf([(\"ada\", 36), (\"grace\", 45)])\n  let older = ages.insert(\"alan\", 41)\n  let seen = #\{\"ada\", \"grace\"\}\n  let counted = evens.length() == 2 && older.size() == 3 && ages.size() == 2\n  if counted && ages.containsKey(\"ada\") && \"grace\" in seen \{ 0 \} else \{ 1 \}\n\}\n```\n"},14  Chapter.Chapter{group: "docs", slug: "numbers", title: "Numbers", markdown: "# Numbers\n\nPudu has whole numbers of every common width, floating-point numbers, exact decimals, and whole numbers of any size. Each is its own type, and no number turns into another without the program saying so.\n\n## Choosing a type\n\n| Type | Use it for | Literal |\n| --- | --- | --- |\n| `Int` | counting, indexing, most arithmetic | `42` |\n| `Int8` … `Int128`, `UInt8` … `UInt128` | a value with a fixed size: a byte, a file offset, a protocol field | `255u8`, `-7i32`, `9000000000i64` |\n| `Float64`, `Float32` | measurements, where a tiny rounding error is acceptable | `3.14`, `1.5f32` |\n| `Decimal` | money, and anything else a person reads as a written number | `19.99d` |\n| `BigInt` | whole numbers that outgrow every fixed width | a whole literal given the type |\n\nA literal with no suffix is an `Int` or a `Float64`. A suffix gives it a width: `u8` through `u128` for unsigned integers, `i8` through `i128` for signed ones, `f32` and `f64` for floats, and `d` for a decimal. Underscores may separate digits: `1_000_000`.\n\n## Arithmetic that cannot go wrong quietly\n\n`+`, `-`, and `*` on a fixed-width integer are checked. A result that does not fit stops the program with a diagnostic naming the type, rather than wrapping around to a small or negative number:\n\n```text\nerror[E7005]: UInt8 cannot hold the result of this add\n   = help: use the wrapping or saturating form, or a wider type; checked arithmetic never truncates quietly\n```\n\nWhen wrapping around or stopping at the limit is what the program means, it says so with an operator of its own:\n\n```pudu\nmodule Arithmetic\n\nfn main() -> Int \{\n  let level: UInt8 = 250u8\n  let wrapped = level &+ 10u8\n  let saturated = level +| 10u8\n  let floor = 3u8 -| 5u8\n  let hashed = 4000000000u32 &* 3u32\n  if wrapped == 4u8 && saturated == 255u8 && floor == 0u8 && hashed == 3410065408u32 \{ 0 \} else \{ 1 \}\n\}\n```\n\n| Operation | Checked | Wrapping | Saturating |\n| --- | --- | --- | --- |\n| add | `+` | `&+` | `+\\|` |\n| subtract | `-` | `&-` | `-\\|` |\n| multiply | `*` | `&*` | `*\\|` |\n\nDivision and remainder by nought have no answer at all, so [Std.Math](/module/Std.Math) offers `Math.divide` and `Math.remainder`, which answer an `Option`.\n\n## Moving between widths\n\nTwo numbers of different types never meet in one operation: `1u8 + 1i32` is refused where it is written. Moving a value to another width goes through `BigInt`, which holds any whole number. Widening is always exact; narrowing answers an `Option`, because the value may not fit:\n\n```pudu\nmodule Widths\n\nimport Std.Num \{Integer\}\n\nfn main() -> Int \{\n  let reading = 300\n  let wide = reading.toBigInt()\n  let asByte = 0u8.fromBigInt(wide)\n  let asShort = 0i16.fromBigInt(wide)\n  if asByte == None && asShort == Some(300i16) \{ 0 \} else \{ 1 \}\n\}\n```\n\nThe receiver of `fromBigInt` only names the type wanted — `0u8` asks for a `UInt8` — so generic code can keep its caller's type.\n\n## Exact decimals\n\nA `Float64` stores a binary fraction, so `0.1 + 0.2` is not quite `0.3`. A `Decimal` stores the digits that were written, so sums of prices come out exact. [Std.Decimal](/module/Std.Decimal) rounds with a named rule, because every rule decides the halfway case differently:\n\n```pudu\nmodule Prices\n\nimport Std.Decimal as D\n\nfn main() -> Int \{\n  let items = [19.99d, 5.01d, 0.10d]\n  let subtotal = D.sum(items)\n  let tax = D.round(subtotal * 0.0825d, 2, D.HalfEven)\n  let total = subtotal + tax\n  let exact = 0.1d + 0.2d == 0.3d\n  if exact && subtotal == 25.10d && tax == 2.07d && D.toText(total) == \"27.17\" \{ 0 \} else \{ 1 \}\n\}\n```\n\nDivision is the one operation that may not terminate in base ten. `D.divide(value, divisor, digits, rule)` says how many digits to keep and how to round the last one, and answers `None` only for a divisor of nought.\n\n## Whole numbers of any size\n\nA `BigInt` grows as it needs to. It is what a program reaches for when a factorial, a checksum, or a counter will not fit in 128 bits:\n\n```pudu\nmodule Factorials\n\nimport Std.Io as Io\n\nfn factorial(n: BigInt) -> BigInt \{\n  var product: BigInt = 1\n  var step: BigInt = 2\n  while step <= n \{\n    product = product * step\n    step = step + 1\n  \}\n  product\n\}\n\nfn main() -> Int \{\n  let big = factorial(30)\n  let _written = Io.writeLine(\"30! = \{big\}\")\n  if \"\{big\}\" == \"265252859812191058636308480000000\" \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Numeric helpers\n\n| Module | Provides |\n| --- | --- |\n| [Std.Math](/module/Std.Math) | `min`, `max`, `clamp`, `abs`, `pow`, `gcd`, `isPrime`, and division that answers an `Option` |\n| [Std.Math.Float](/module/Std.Math.Float) | `sqrt`, `floor`, `round`, trigonometry, logarithms, and the constants `pi()` and `e()` |\n| [Std.Decimal](/module/Std.Decimal) | rounding rules, exact division, parsing, and formatting decimals |\n| [Std.Num](/module/Std.Num) | the traits generic numeric code asks for, and conversion through `BigInt` |\n| [Std.Bits](/module/Std.Bits) | bitwise operations, shifts, and counting bits |\n| [Std.Random](/module/Std.Random) | seeded and clock-driven random numbers |\n"},15  Chapter.Chapter{group: "docs", slug: "text", title: "Text", markdown: "# Text\n\nText in Pudu is the `Str` type: a sequence of Unicode characters stored as UTF-8. A single character is a `Char`. This chapter covers writing text, placing values inside it, and the everyday operations on it.\n\n## Writing text\n\nText is written between double quotes. A backslash writes a character that would otherwise end or change the text:\n\n| Escape | Character |\n| --- | --- |\n| `\\n` | a line break |\n| `\\t` | a tab |\n| `\\\"` | a double quote |\n| `\\\\` | a backslash |\n| `\\\{` and `\\\}` | braces, when they are not an interpolation |\n\nA `Char` is written between single quotes: `'a'`, `'\\n'`.\n\n## Placing values inside text\n\nAn expression between braces inside text is evaluated and written in its place. Any value can be placed, and the expression can be more than a name:\n\n```pudu\nmodule Interpolation\n\nfn main() -> Int \{\n  let name = \"Ada\"\n  let year = 1843\n  let sentence = \"\{name\} published her notes in \{year\}, \{2024 - year\} years ago.\"\n  let braces = \"a set is written \\\{1, 2, 3\\\}\"\n  if sentence == \"Ada published her notes in 1843, 181 years ago.\" && braces.startsWith(\"a set\") \{ 0 \} else \{ 1 \}\n\}\n```\n\nText can also be joined with `+`, which is handy when the pieces are already values: `first + \" \" + last`.\n\n## Asking questions about text\n\n```pudu\nmodule Questions\n\nfn main() -> Int \{\n  let title = \"The Analytical Engine\"\n  let checks = [\n    title.length() == 21,\n    !title.isEmpty(),\n    title.contains(\"Engine\"),\n    title.startsWith(\"The\"),\n    title.endsWith(\"Engine\"),\n    title.indexOf(\"Analytical\") == 4,\n    title.indexOf(\"Difference\") == -1\n  ]\n  if checks.filter(fn(held: Bool) => !held).isEmpty() \{ 0 \} else \{ 1 \}\n\}\n```\n\n`length()` counts characters, not bytes, so `\"héllo\".length()` is `5`. `indexOf` answers `-1` when the text does not occur.\n\n## Changing text\n\nText never changes in place. Every operation answers new text and leaves the original as it was:\n\n```pudu\nmodule Changes\n\nfn main() -> Int \{\n  let raw = \"  Hello, World  \"\n  let tidy = raw.trim()\n  let shouted = tidy.toUpper()\n  let quiet = tidy.toLower()\n  let swapped = tidy.replace(\"World\", \"Pudu\")\n  let first = tidy.take(5)\n  let rest = tidy.drop(7)\n  let middle = tidy.slice(2, 5)\n  let echo = \"ha\".repeat(3)\n  let ok = tidy == \"Hello, World\" && shouted == \"HELLO, WORLD\" && quiet == \"hello, world\"\n  if ok && swapped == \"Hello, Pudu\" && first == \"Hello\" && rest == \"World\" && middle == \"llo\" && echo == \"hahaha\" \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Splitting and joining\n\n`split` breaks text on a separator, and `join` on an array puts pieces back together. `lines` splits on line breaks:\n\n```pudu\nmodule Splitting\n\nimport Std.Text as Text\n\nfn main() -> Int \{\n  let csvRow = \"ada,grace,alan\"\n  let names = csvRow.split(\",\")\n  let joined = names.join(\" and \")\n  let poem = \"roses are red\\nviolets are blue\"\n  let words = Text.words(\"the quick  brown fox\")\n  let ok = names.length() == 3 && joined == \"ada and grace and alan\"\n  if ok && poem.lines().length() == 2 && words == [\"the\", \"quick\", \"brown\", \"fox\"] \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Characters\n\n`chars()` answers every character of a text, and `for` walks text one character at a time. Characters compare in Unicode order, and `code()` gives a character's number:\n\n```pudu\nmodule Characters\n\nfn isVowel(letter: Char) -> Bool \{\n  letter == 'a' || letter == 'e' || letter == 'i' || letter == 'o' || letter == 'u'\n\}\n\nfn main() -> Int \{\n  var vowels = 0\n  var digits = 0\n  for letter in \"pudu 2026\" \{\n    if isVowel(letter) \{ vowels = vowels + 1 \}\n    if letter >= '0' && letter <= '9' \{ digits = digits + 1 \}\n  \}\n  let letters = \"abc\".chars()\n  if vowels == 2 && digits == 4 && letters.length() == 3 && 'A'.code() == 65 \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Reading numbers from text\n\nText that should be a number is read with `Std.Text`. The answer is an `Option`, because the text may not be a number at all:\n\n```pudu\nmodule Numbers\n\nimport Std.Option as Option\nimport Std.Text as Text\n\nfn portFrom(written: Str) -> Int \{\n  Option.unwrapOr(Text.wholeOf(written.trim()), 8080)\n\}\n\nfn main() -> Int \{\n  if portFrom(\" 3000 \") == 3000 && portFrom(\"http\") == 8080 \{ 0 \} else \{ 1 \}\n\}\n```\n\nGoing the other way, any value placed inside text is written as text: `\"\{3000\}\"` is `\"3000\"`.\n\n## Std.Text\n\nThe built-in methods cover the everyday work. [Std.Text](/module/Std.Text) adds the rest, as functions that take the text as their first argument:\n\n| Function | Answers |\n| --- | --- |\n| `Text.wholeOf(text)` | the whole number the text spells, or `None` |\n| `Text.words(text)` | the words, split on spaces |\n| `Text.capitalize(text)` | the text with its first character in upper case |\n| `Text.padLeft(text, width, fill)` | the text padded on the left to a width |\n| `Text.countOccurrences(text, needle)` | how many times a needle occurs |\n| `Text.isBlank(text)` | whether the text holds only whitespace |\n\n```pudu\nmodule Formatting\n\nimport Std.Text as Text\n\nfn row(name: Str, score: Int) -> Str \{\n  Text.padRight(Text.capitalize(name), 8, \".\") + Text.padLeft(\"\{score\}\", 4, \" \")\n\}\n\nfn main() -> Int \{\n  let table = [row(\"ada\", 95), row(\"grace\", 100)]\n  if table[0] == \"Ada.....  95\" && table[1] == \"Grace... 100\" \{ 0 \} else \{ 1 \}\n\}\n```\n"},16  Chapter.Chapter{group: "docs", slug: "collections", title: "Collections", markdown: "# Collections\n\nMost programs hold many values at once. Pudu has three built-in collections — arrays, maps, and sets — and the standard library adds more for special shapes of data. This chapter covers the three you will use every day.\n\n| Collection | Holds | Written |\n| --- | --- | --- |\n| `Array[T]` | values in order, reached by position | `[1, 2, 3]` |\n| `Map[K, V]` | values reached by a key, kept in key order | `mapOf([(\"ada\", 36)])` |\n| `Set[T]` | distinct values, kept in order | `#\{\"red\", \"green\"\}` |\n\nCollection operations answer new collections rather than changing the old one. Binding the result to a `var` is how a collection grows over time.\n\n## Arrays\n\nAn array holds values of one type in order. `items[i]` reads the value at a position, counting from zero:\n\n```pudu\nmodule Arrays\n\nfn main() -> Int \{\n  let primes = [2, 3, 5, 7]\n  let first = primes[0]\n  let longer = primes.push(11)\n  let front = longer.slice(0, 2)\n  let both = primes.concat([13, 17])\n  let ok = first == 2 && primes.length() == 4 && longer.length() == 5\n  if ok && front == [2, 3] && both.length() == 6 && primes.contains(5) \{ 0 \} else \{ 1 \}\n\}\n```\n\n`push` answered a new array, so `primes` still has four elements. Reading a position that is not there stops the program; `items.get(i)` answers an `Option` instead when a position might be missing.\n\n## Ranges and slices\n\nA range is two ends written with `..`, or `..=` when the last value is included. It is a value: it\ncan be named, passed to a function, and asked questions. It does not build the numbers it covers, so\na range over millions of values costs the same as a range over three:\n\n```pudu\nmodule Ranges\n\nfn main() -> Int \{\n  let span = 1..4\n  let inclusive = 1..=4\n\n  var total = 0\n  for n in 0..1000 \{\n    total = total + n\n  \}\n\n  if span.length() == 3\n    && inclusive.length() == 4\n    && span.contains(2)\n    && span.toArray() == [1, 2, 3]\n    && span.map(|n| n * n) == [1, 4, 9]\n    && span.sum() == 6\n    && total == 499500\n  \{\n    0\n  \} else \{\n    1\n  \}\n\}\n```\n\nIndexing with a range reads a stretch rather than one value. Either end may be left off, and the\nvalue being indexed supplies the one that is missing:\n\n```pudu\nmodule Slices\n\nfn main() -> Int \{\n  let primes = [2, 3, 5, 7, 11]\n  let middle = primes[1..3]\n  let tail = primes[2..]\n  let front = primes[..2]\n  let whole = primes[..]\n  let upToAndIncluding = primes[1..=3]\n\n  let text = \"hello world\"\n  let greeting = text[0..5]\n\n  if middle == [3, 5]\n    && tail == [5, 7, 11]\n    && front == [2, 3]\n    && whole.length() == 5\n    && upToAndIncluding == [3, 5, 7]\n    && greeting == \"hello\"\n  \{\n    0\n  \} else \{\n    1\n  \}\n\}\n```\n\nA slice that reaches past the end stops the program, the same way reading a position that is not\nthere does. It is not quietly shortened, because a shorter answer would hide the arithmetic that\nasked for too much.\n\n## Building an array step by step\n\nA `var` holding an array grows one value at a time:\n\n```pudu\nmodule Building\n\nfn squaresBelow(limit: Int) -> Array[Int] \{\n  var squares: Array[Int] = []\n  var n = 1\n  while n * n < limit \{\n    squares = squares.push(n * n)\n    n = n + 1\n  \}\n  squares\n\}\n\nfn main() -> Int \{\n  if squaresBelow(30) == [1, 4, 9, 16, 25] \{ 0 \} else \{ 1 \}\n\}\n```\n\nAn empty array needs its type written, `Array[Int]`, because there is nothing in it for the compiler to learn the type from.\n\n## Transforming arrays\n\n`map`, `filter`, and `reduce` take a function and apply it across an array:\n\n```pudu\nmodule Transforming\n\ntype Order = \{ item: Str, price: Int, quantity: Int \}\n\nfn main() -> Int \{\n  let orders = [\n    Order\{item: \"tea\", price: 4, quantity: 3\},\n    Order\{item: \"cake\", price: 6, quantity: 1\},\n    Order\{item: \"coffee\", price: 5, quantity: 2\}\n  ]\n  let totals = orders.map(fn(order: Order) => order.price * order.quantity)\n  let large = orders.filter(fn(order: Order) => order.quantity > 1)\n  let revenue = totals.reduce(fn(sum: Int, total: Int) => sum + total, 0)\n  if totals == [12, 6, 10] && large.length() == 2 && revenue == 28 \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Std.List\n\n[Std.List](/module/Std.List) holds dozens more operations on arrays: sorting, searching, grouping, and combining.\n\n```pudu\nmodule Lists\n\nimport Std.List as List\nimport Std.Option as Option\n\nfn main() -> Int \{\n  let scores = [72, 95, 88, 61, 95]\n  let ranked = List.sorted(&scores)\n  let best = Option.unwrapOr(List.maximum(&scores), 0)\n  let passing = List.countWhere(&scores, fn(score: Int) => score >= 70)\n  let unique = List.distinct(&scores)\n  let named = List.zip(&[\"ada\", \"grace\"], &[95, 88])\n  let ok = ranked == [61, 72, 88, 95, 95] && best == 95 && passing == 4\n  if ok && unique.length() == 4 && named[1] == (\"grace\", 88) \{ 0 \} else \{ 1 \}\n\}\n```\n\n| Function | Answers |\n| --- | --- |\n| `List.sorted(&items)` | the items in ascending order |\n| `List.sortOn(&items, key)` | the items ordered by a key drawn from each |\n| `List.find(&items, test)` | the first item the test accepts, or `None` |\n| `List.fold(&items, combine, start)` | every item combined into one value |\n| `List.partition(&items, test)` | the items the test accepts and the ones it rejects |\n| `List.range(from, to)` | the whole numbers from `from` up to `to` |\n\n## Maps\n\nA map stores a value under each key. `get` answers an `Option`, because the key may have no entry:\n\n```pudu\nmodule Maps\n\nimport Std.Map as Map\nimport Std.Option as Option\n\nfn main() -> Int \{\n  let ages = mapOf([(\"ada\", 36), (\"grace\", 85)])\n  let withAlan = ages.insert(\"alan\", 41)\n  let adaAge = Option.unwrapOr(withAlan.get(\"ada\"), 0)\n  let missing = withAlan.get(\"linus\")\n  let withoutGrace = withAlan.remove(\"grace\")\n  let names = withAlan.keys()\n  let ok = adaAge == 36 && missing == None && withoutGrace.size() == 2\n  if ok && names == [\"ada\", \"alan\", \"grace\"] && Map.getOr(&ages, \"linus\", 0) == 0 \{ 0 \} else \{ 1 \}\n\}\n```\n\nKeys are kept in order, so `keys()` and a `for` loop visit them sorted. A `for` loop over a map walks `(key, value)` pairs:\n\n```pudu\nmodule Counting\n\nimport Std.Map as Map\nimport Std.Option as Option\n\nfn wordCounts(text: Str) -> Map[Str, Int] \{\n  var counts: Map[Str, Int] = mapOf([])\n  for word in text.split(\" \") \{\n    let seen = Option.unwrapOr(counts.get(word), 0)\n    counts = counts.insert(word, seen + 1)\n  \}\n  counts\n\}\n\nfn main() -> Int \{\n  let counts = wordCounts(\"the cat saw the other cat\")\n  var lines: Array[Str] = []\n  for (word, count) in counts \{\n    lines = lines.push(\"\{word\}: \{count\}\")\n  \}\n  let same = counts == Map.tally(&\"the cat saw the other cat\".split(\" \"))\n  if lines[0] == \"cat: 2\" && lines.length() == 4 && same \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Sets\n\nA set holds each value at most once. `in` asks whether a value is a member:\n\n```pudu\nmodule Sets\n\nfn main() -> Int \{\n  let warm = #\{\"red\", \"orange\", \"yellow\"\}\n  let flag = #\{\"red\", \"white\", \"blue\"\}\n  let both = warm.intersect(flag)\n  let either = warm.union(flag)\n  let onlyWarm = warm.difference(flag)\n  let grown = warm.insert(\"red\").insert(\"pink\")\n  let ok = \"red\" in both && both.size() == 1 && either.size() == 5\n  if ok && onlyWarm.size() == 2 && grown.size() == 4 && !(\"green\" in warm) \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Choosing a collection\n\n- Reach for an **array** when order matters or you will walk every value.\n- Reach for a **map** when you look values up by something other than their position.\n- Reach for a **set** when all you need to know is whether something is there.\n\nThe standard library has more specialised collections when these three do not fit — double-ended queues, priority queues, hash maps, tries, and graphs. The [standard library](/docs/standard-library) chapter maps them out.\n"},17  Chapter.Chapter{group: "docs", slug: "control-flow", title: "Control flow", markdown: "# Control flow\n\nPudu's control flow is made of expressions: `if` and `match` produce values, and a `loop` can produce the value it was searching for.\n\n## if\n\n`if` is an expression. Every branch that can be reached must produce the same type:\n\n```pudu\nmodule Grades\n\nfn letter(score: Int) -> Str \{\n  if score >= 90 \{ \"A\" \} else if score >= 80 \{ \"B\" \} else \{ \"C\" \}\n\}\n\nfn main() -> Int \{\n  if letter(95) == \"A\" && letter(70) == \"C\" \{ 0 \} else \{ 1 \}\n\}\n```\n\n## match\n\n`match` compares a value against patterns, top to bottom, and runs the first arm that fits. Every arm starts with `case`, and an arm may add a guard with `if`. A `match` must cover every shape the value can have:\n\n```pudu\nmodule Matching\n\nfn describe(value: Option[Int]) -> Str \{\n  match value \{\n    case Some(score) if score >= 90 => \"excellent\"\n    case Some(score) => \"scored \{score\}\"\n    case None => \"no score\"\n  \}\n\}\n\nfn main() -> Int \{\n  if describe(Some(95)) == \"excellent\" && describe(None) == \"no score\" \{ 0 \} else \{ 1 \}\n\}\n```\n\nPatterns include literals, ranges such as `1..=9`, alternatives joined with `|`, tuples, records, and variants. `_` matches anything and binds nothing.\n\n## if let\n\n`if let` tests one pattern without writing a whole `match`. The names it binds exist only inside its block:\n\n```pudu\nmodule Lookup\n\nfn firstFailing(scores: &Array[Int]) -> Option[Int] \{\n  for score in *scores \{\n    if score < 60 \{ return Some(score) \}\n  \}\n  None\n\}\n\nfn main() -> Int \{\n  if let Some(failing) = firstFailing(&[95, 82, 47]) \{\n    failing - 47\n  \} else \{\n    1\n  \}\n\}\n```\n\n## let … else\n\n`let PATTERN = value else \{ ... \}` binds a pattern for the rest of the block. The `else` block runs when the pattern does not match, and it must leave — with `return`, `break`, or `continue` — so every line after it can rely on the binding:\n\n```pudu\nmodule Early\n\nimport Std.Text as Text\n\nfn portOf(text: Str) -> Int \{\n  let Some(port) = Text.wholeOf(text) else \{ return 0 \}\n  port\n\}\n\nfn main() -> Int \{\n  if portOf(\"8080\") == 8080 && portOf(\"http\") == 0 \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Loops\n\n| Loop | Runs |\n| --- | --- |\n| `while condition \{ ... \}` | while the condition holds |\n| `while let PATTERN = value \{ ... \}` | while the pattern matches |\n| `for item in collection \{ ... \}` | once for each item |\n| `loop \{ ... \}` | until a `break` |\n\n`for` walks arrays, text (one `Char` at a time), sets, maps (as `(key, value)` pairs), and any type that implements `Std.Iter.Sequence`. A `loop` is an expression whose value is what its `break` carries:\n\n```pudu\nmodule Search\n\nfn main() -> Int \{\n  var total = 0\n  for score in [95, 82, 47] \{\n    total = total + score\n  \}\n  var remaining = total\n  let found = loop \{\n    remaining = remaining - 10\n    if remaining < 100 \{ break remaining \}\n  \}\n  if found < 100 \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Labels\n\n`break` and `continue` act on the nearest loop. A label written `@name` before a loop lets an inner loop leave an outer one:\n\n```pudu\nmodule Labels\n\nfn main() -> Int \{\n  var found = 0\n  @rows for row in [1, 2, 3] \{\n    for column in [1, 2, 3] \{\n      if row * column == 6 \{\n        found = row * 10 + column\n        break @rows\n      \}\n    \}\n  \}\n  if found == 23 \{ 0 \} else \{ 1 \}\n\}\n```\n"},18  Chapter.Chapter{group: "docs", slug: "errors", title: "Errors", markdown: "# Errors\n\nPudu has no exceptions. Work that can fail says so in its type, and the caller decides what happens next.\n\n## Result\n\nA function that can fail returns `Result[T, E]`: `Ok(value)` when it succeeded and `Err(problem)` when it did not. The problem can be any type, and a sum type of the ways the work can fail is usually the most useful one:\n\n```pudu\nmodule Settings\n\nimport Std.Io as Io\nimport Std.Text as Text\n\ntype SettingError = | Missing(Str) | NotANumber(Str)\n\nfn portFrom(text: Str) -> Result[Int, SettingError] \{\n  if text.isEmpty() \{ return Err(Missing(\"port\")) \}\n  match Text.wholeOf(text) \{\n    case Some(port) => Ok(port)\n    case None => Err(NotANumber(text))\n  \}\n\}\n\nfn address(host: Str, port: Str) -> Result[Str, SettingError] \{\n  let number = portFrom(port) ?\n  Ok(\"\{host\}:\{number\}\")\n\}\n\nfn main() -> Int \{\n  match address(\"127.0.0.1\", \"8080\") \{\n    case Ok(text) => \{\n      let _written = Io.writeLine(text)\n      0\n    \}\n    case Err(Missing(name)) => \{\n      let _written = Io.writeLine(\"missing \{name\}\")\n      1\n    \}\n    case Err(NotANumber(text)) => \{\n      let _written = Io.writeLine(\"not a number: \{text\}\")\n      1\n    \}\n  \}\n\}\n```\n\n## The ? operator\n\nA `?` after a `Result` gives the value inside `Ok`, or returns the `Err` from the current function straight away. In `address` above, `portFrom(port) ?` either yields the port or ends `address` with the same error.\n\n`?` works the same way on `Option` inside a function that returns `Option`: `Some(value)?` gives the value, and `None?` returns `None`. Which one is meant comes from the function's own return type.\n\n```pudu\nmodule Chains\n\nimport Std.Text as Text\n\nfn sum(left: Str, right: Str) -> Option[Int] \{\n  let a = Text.wholeOf(left) ?\n  let b = Text.wholeOf(right) ?\n  Some(a + b)\n\}\n\nfn main() -> Int \{\n  if sum(\"2\", \"40\") == Some(42) && sum(\"2\", \"x\") == None \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Working with results\n\n`Std.Result` and `Std.Option` hold the helpers for the common cases:\n\n| Helper | Does |\n| --- | --- |\n| `Result.unwrapOr(result, fallback)` | the value, or a fallback when it failed |\n| `Result.mapErr(result, change)` | the same result with its error changed |\n| `Result.isOk(&result)` | whether it succeeded |\n| `Option.unwrapOr(option, fallback)` | the value, or a fallback when it is absent |\n\n## Effects return results too\n\nReading a file, writing output, reading an environment variable, and every other effect answers a `Result` rather than stopping the program. That is why the examples in these pages write `let _written = Io.writeLine(...)`: the name makes it visible that the result of writing was received and deliberately set aside.\n\n## Panics\n\nA panic stops the program. It is reserved for a broken internal invariant — an index outside an array, a fixed-width number that no longer fits — never for an ordinary failure such as a missing file or bad input. Anything a caller could reasonably handle is a `Result`.\n"},19  Chapter.Chapter{group: "docs", slug: "ownership", title: "Ownership and references", markdown: "# Ownership and references\n\nA Pudu value has one owner, and what may change is written where a reader can see it: `var` on a binding, `mut` on a record field, and `&mut` in a signature and at the call. This page covers how values move, how a function borrows a value to read it or to change it, and what the checker refuses.\n\n## Owned values\n\nValues are owned by default. Assigning a value, or passing it to a function by value, moves it. Numbers, booleans, characters, unit, and shared references are copied instead, because copying them is free and leaves nothing behind.\n\n## let and var\n\nA `let` binding never changes. A `var` binding may be assigned again:\n\n```pudu\nmodule Totals\n\nfn main() -> Int \{\n  let limit = 3\n  var total = 0\n  var round = 0\n  while round < limit \{\n    total = total + round\n    round = round + 1\n  \}\n  if total == 3 \{ 0 \} else \{ 1 \}\n\}\n```\n\nAssigning to a `let`, a parameter, or a name bound by a pattern is refused with `E3078`. To work with a changing copy of a parameter, bind it again: `var remaining = count`.\n\n## Borrowing with & and &mut\n\n| Type | Meaning |\n| --- | --- |\n| `&T` | a shared borrow: read the value, do not change it |\n| `&mut T` | an exclusive borrow: the one place allowed to change the value |\n\nA borrow is written at the call as well as in the signature, and `*` reads or writes through a reference:\n\n```pudu\nmodule Scores\n\nfn read(score: &Int) -> Int \{ *score \}\n\nfn award(score: &mut Int, points: Int) -> () \{\n  *score = *score + points\n\}\n\nfn main() -> Int \{\n  var score = 40\n  award(&mut score, 2)\n  if read(&score) == 42 \{ 0 \} else \{ 1 \}\n\}\n```\n\n`award(&mut score, 2)` lends the variable `score` to the call. Whatever `award` stores through its parameter is in `score` when the call returns — whether the function finished normally, left early with `return`, or left through `?`.\n\nThere is no implicit conversion between a value and a reference in either direction: a value where a reference is wanted must be borrowed, and a reference where a value is wanted must be dereferenced. A field reached through a reference needs no `*`, so `user.name` works whether `user` is a `User` or a `&User`.\n\n## Records with mut fields\n\nA record field changes only when its type declares it `mut`, and only through a binding that may change: a `var`, or a `&mut` borrow. A method that changes its receiver takes `self: &mut Self`, and is called on a receiver that could itself be assigned:\n\n```pudu\nmodule Counters\n\ntype Counter = \{ mut count: Int, label: Str \}\n\ntrait Tick \{\n  fn tick(self: &mut Self) -> ()\n\}\n\nimpl Tick for Counter \{\n  fn tick(self: &mut Self) -> () \{\n    self.count = self.count + 1\n  \}\n\}\n\nfn main() -> Int \{\n  var clicks = Counter\{count: 0, label: \"clicks\"\}\n  clicks.tick()\n  clicks.tick()\n  clicks.count = clicks.count + 1\n  if clicks.count == 3 && clicks.label == \"clicks\" \{ 0 \} else \{ 1 \}\n\}\n```\n\n`label` is not declared `mut`, so `clicks.label = \"taps\"` is refused with `E3079`. A whole new value can always be built instead, with `Counter\{..clicks, label: \"taps\"\}`.\n\n## Elements of arrays\n\nAn element of an array is a place too:\n\n```pudu\nmodule Scaling\n\nfn double(values: &mut Array[Int]) -> () \{\n  var index = 0\n  while index < values.length() \{\n    values[index] = values[index] * 2\n    index = index + 1\n  \}\n\}\n\nfn main() -> Int \{\n  var prices = [10, 20, 30]\n  double(&mut prices)\n  prices[0] = 1\n  if prices[0] == 1 && prices[2] == 60 \{ 0 \} else \{ 1 \}\n\}\n```\n\nThe methods on a collection still answer new values: `prices.push(40)` gives a longer array and leaves `prices` as it was, so writing it as a statement on its own does nothing and is reported as a warning. Text, tuples, and maps have no element places; `counts = counts.insert(key, value)` is how a map changes.\n\n## Two borrows of one place\n\nA call may be lent several places, but not the same one twice, and not a place together with something that contains it:\n\n```pudu\nmodule Swaps\n\ntype Pair = \{ mut left: Int, mut right: Int \}\n\nfn exchange(first: &mut Int, second: &mut Int) -> () \{\n  let held = *first\n  *first = *second\n  *second = held\n\}\n\nfn main() -> Int \{\n  var pair = Pair\{left: 1, right: 2\}\n  exchange(&mut pair.left, &mut pair.right)\n  if pair.left == 2 && pair.right == 1 \{ 0 \} else \{ 1 \}\n\}\n```\n\n`exchange(&mut pair.left, &mut pair.left)` is refused with `E3082`, and so is lending `&mut pair` beside `&mut pair.left`.\n\n## Where &mut may appear\n\nAn exclusive borrow lasts exactly as long as the call it was lent to. So `&mut T` is only ever the type of a parameter, and `&mut place` is only ever written as an argument. It is refused as a function's result, in a binding, in a record field or variant, inside another type such as `Option[&mut Int]`, as a parameter of an `async fn`, and in a closure that captures one. A function that holds a `&mut` parameter may lend it on by name: `award(score, 1)`.\n\n| Code | Refused |\n| --- | --- |\n| `E3076` | a change to a name a closure captured |\n| `E3077` | an assignment to something that is not a place |\n| `E3078` | a change to a binding not declared `var` |\n| `E3079` | an assignment to a field not declared `mut` |\n| `E3080` | a change through a shared reference `&T` |\n| `E3081` | `&mut` written anywhere but a call argument |\n| `E3082` | two borrows of overlapping places in one call |\n| `E3083` | `&mut` in a type position other than a parameter |\n| `E3084` | an exclusive borrow kept in a binding, a result, a closure, or another value |\n\n## Closures capture copies\n\nA function literal captures the bindings around it by copying them. Assigning to a captured name would change only the copy, so the language refuses it with `E3076` and asks for the new value to be returned instead:\n\n```pudu\nmodule Capture\n\nfn main() -> Int \{\n  let base = 10\n  let addBase = fn(n: Int) => n + base\n  if addBase(32) == 42 \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Resources\n\nResources such as files, sockets, and database connections are released when their owner is done with them. Where release can fail or must happen at a particular point, the standard library gives an explicit `close` and a scoped form — such as `Io.withReader` — that releases the resource however the work inside it ended. A resource a C library hands back is declared with the function that releases it; see [unsafe and foreign code](/docs/foreign-code).\n"},20  Chapter.Chapter{group: "docs", slug: "modules", title: "Modules and packages", markdown: "# Modules and packages\n\nA program grows past one file by splitting into modules. This chapter covers how a module names itself, what it shows to other modules, the ways to import, and how a project and its dependencies are described.\n\n## A module is a file\n\nEvery file declares exactly one module, and the module's name is the file's path with dots for directories. Inside a project whose source lives in `src`:\n\n| File | Module |\n| --- | --- |\n| `src/Main.pudu` | `module Main` |\n| `src/Shapes/Area.pudu` | `module Shapes.Area` |\n| `src/Shapes/Perimeter.pudu` | `module Shapes.Perimeter` |\n\nA file holds declarations only — functions, types, traits, implementations, and constants. Nothing runs when a module is loaded, so importing a module can never have a side effect.\n\n## What a module shows\n\nDeclarations are private unless they are marked `export`. An exported function writes out every parameter type and its return type, and an exported constant writes out its type, because other modules are checked against those signatures alone:\n\n```pudu\nmodule Shapes.Area\n\n/// The ratio of a circle's circumference to its diameter, to five places.\nexport const PI: Float64 = 3.14159\n\n/// The area of a circle.\nexport fn circle(radius: Float64) -> Float64 \{\n  PI * square(radius)\n\}\n\n/// The area of a rectangle.\nexport fn rectangle(width: Float64, height: Float64) -> Float64 \{\n  width * height\n\}\n\nfn square(value: Float64) -> Float64 = value * value\n\nfn main() -> Int \{\n  if rectangle(2.0, 3.0) == 6.0 && circle(1.0) == PI \{ 0 \} else \{ 1 \}\n\}\n```\n\n`square` has no `export`, so it is an implementation detail other modules cannot call.\n\n## Importing\n\nA second file imports the first by its full name:\n\n```pudu\nmodule Main\n\nimport Std.Io as Io\nimport Shapes.Area as Area\n\nexport fn main() -> Int \{\n  let total = Area.rectangle(2.0, 3.0) + Area.circle(1.0)\n  match Io.writeLine(\"total area: \{total\}\") \{\n    case Ok(_) => 0\n    case Err(_) => 1\n  \}\n\}\n```\n\nImports are always absolute — there is no importing relative to the current file — and there are three forms:\n\n| Form | Binds | Used as |\n| --- | --- | --- |\n| `import Shapes.Area` | the module under the last segment of its name | `Area.circle(1.0)` |\n| `import Shapes.Area as Area` | the module under a short name | `Area.circle(1.0)` |\n| `import Shapes.Area \{circle, PI\}` | the named declarations | `circle(1.0)`, `PI` |\n\nThe alias form is the one most code uses: it is short, and every use still says where the name came from. Selecting names reads well for a few that are used constantly:\n\n```pudu\nmodule Selected\n\nimport Std.Option \{unwrapOr\}\nimport Std.Text \{wholeOf\}\n\nfn main() -> Int \{\n  let port = unwrapOr(wholeOf(\"8080\"), 80)\n  if port == 8080 \{ 0 \} else \{ 1 \}\n\}\n```\n\nThere are no wildcard imports, so the answer to \"where does this name come from?\" is always in the import list at the top of the file.\n\n## Constants\n\nA `const` is a value computed while the program is compiled. It can use arithmetic, text, collections, and other constants, and a module can export one:\n\n```pudu\nmodule Limits\n\nconst KILOBYTE: Int = 1024\n\nconst UPLOAD_LIMIT: Int = 8 * KILOBYTE * KILOBYTE\n\nconst SUPPORTED: Array[Str] = [\"png\", \"jpeg\", \"webp\"]\n\nconst LABELS: Map[Str, Str] = mapOf([(\"png\", \"PNG image\"), (\"webp\", \"WebP image\")])\n\nfn accepts(extension: Str, size: Int) -> Bool \{\n  SUPPORTED.contains(extension) && size <= UPLOAD_LIMIT\n\}\n\nfn main() -> Int \{\n  let labelled = LABELS.get(\"png\") == Some(\"PNG image\")\n  if accepts(\"png\", 4096) && !accepts(\"gif\", 10) && labelled \{ 0 \} else \{ 1 \}\n\}\n```\n\nA constant table like `LABELS` is often the clearest way to write a lookup: the data is in one place, and the code that reads it stays short.\n\n## The manifest\n\nA project is described by `pudu.toml` at its root:\n\n```toml\n[package]\nname = \"shapes\"\nversion = \"0.1.0\"\nlanguage = \">=0.1.0 <0.2.0\"\nsource = \"src\"\n\n[dependencies]\nsrc = \"src\"\ngeometry = \"../geometry\"\n```\n\n| Key | Means |\n| --- | --- |\n| `name` | the package's name, in lower case |\n| `version` | the package's own version |\n| `language` | the Pudu versions it works with |\n| `source` | the directory its modules live under |\n| `root` | the module root the package owns; its name in PascalCase when left out |\n| `[dependencies]` | the code this package uses: directories, repositories, and published packages, each under a name |\n\nA dependency's modules are imported by their own names, exactly like the package's own. [Dependencies](/docs/dependencies) covers adding them with `pudu install`, the lock file, and `deps/`.\n\n## Organising a project\n\n`pudu init` lays a project out in three layers, and larger programs tend to keep them:\n\n- **`Domain`** modules hold the rules of the problem as pure functions and types, with no input or output.\n- **`App`** modules use the domain to do one job a user asks for.\n- **`Main`** reads the outside world — arguments, files, the network — calls the application, and reports.\n\nDependencies point inward: `Main` imports `App`, `App` imports `Domain`, and `Domain` imports only the standard library. The domain is then the easiest code to test, because it needs nothing but values.\n"},21  Chapter.Chapter{group: "docs", slug: "dependencies", title: "Dependencies", markdown: "# Dependencies\n\nA project uses code other people wrote by naming it in `pudu.toml` and running `pudu install`. The command chooses a version of everything needed, records the choice and a digest of its content in `pudu.lock`, and puts the code in `deps/`, where the compiler, the editor, and you can all read it. There is no second tool: every command on this page is part of `pudu`.\n\n## Installing a dependency\n\nName what you want to install: a package from GitHub, a directory on your machine, or a git repository at a tag, branch, or commit:\n\n```sh\npudu install @alice/json-schema\npudu install @alice/json-schema@1.4.2\npudu install ../geometry\npudu install https://github.com/carol/parser.git#v0.4.0\n```\n\nA package is `@owner/repo`, the GitHub repository `github.com/owner/repo`, and its releases are its version tags (`v1.4.2`). Without a version, `pudu install` takes the newest release and writes a requirement compatible with it (`^1.4.2`); with `@1.4.2` it takes exactly that release.\n\nWhile it works, one line at the bottom of the terminal shows what it is doing — fetching a repository, copying a package — and how long it has taken. When it is done, `pudu install` says where each package came from, what changed, and what to import:\n\n```text\nResolved 1 package in 612ms · 1 fetched\nPackages: +1\n  + parser 0.4.0\nInstalled 1 package into deps/ in 21ms\nWrote pudu.toml, pudu.lock\n\nparser provides the modules under Parser, such as:\n  import Parser.Json\n\nDone in 640ms\n```\n\nRun it again and nothing is fetched: the lock names a commit the machine already has.\n\n```text\nResolved 1 package in 1ms · 1 from cache\nAlready up to date\n\nDone in 9ms\n```\n\n`--verbose` prints every step as its own timed line, which is what to read when something is slow; `--quiet` prints nothing unless there is an error.\n\nA dependency's modules are imported by their names, exactly like the project's own:\n\n```text\nimport Parser.Json as Json\n```\n\n`pudu check`, `pudu run`, `pudu test`, and the editor find installed packages without being told.\n\n## What gets written\n\n`pudu.toml` gains one line for each dependency. A directory is used where it is; a repository is checked out at the revision named:\n\n```toml\n[dependencies]\ngeometry = \{ path = \"../geometry\" \}\nparser = \{ git = \"https://github.com/carol/parser.git\", rev = \"v0.4.0\" \}\n```\n\n`pudu.lock` records exactly what was installed: the commit the tag pointed to and a digest of every file the package contains. Commit it. Anyone who runs `pudu install` in a checkout of the project gets the same files, even if the tag has since been moved.\n\n`deps/` holds the installed code. Do not commit it — `pudu init` adds it to `.gitignore` — and do not edit it: `pudu install` notices a changed file and puts the original back.\n\n## Keeping it reproducible\n\n| Command | Does |\n| --- | --- |\n| `pudu install` | installs exactly what `pudu.lock` names, writing the lock first if there is none |\n| `pudu install --locked` | fails instead of changing `pudu.lock` — for continuous integration |\n| `pudu install --offline` | uses only what is already downloaded, and fails rather than reaching the network |\n| `pudu update [name]` | moves to the newest revision or release the manifest allows |\n| `pudu uninstall <name>` | removes a dependency from the manifest, the lock, and `deps/` |\n| `pudu deps` | lists the direct dependencies and what is locked for each |\n| `pudu tree` | shows every package the project uses, and what uses it |\n\nDownloads are kept in `~/.pudu/cache` (or `$PUDU_HOME/cache`) and shared by every project on the machine, so a second project using the same commit copies files and downloads nothing. With a lock present and the cache holding what it names, `pudu install` makes no network request and runs no git command, and `pudu check`, `run`, and `test` never touch the network. Repositories are fetched and packages copied side by side, and a package is copied again only if its files in `deps/` changed; a cached copy whose files no longer match `pudu.lock` is refused rather than installed.\n\n## Publishing a package\n\nA package is a GitHub repository with a `pudu.toml` naming it `@owner/repo`. There is no separate registry to sign up for: a release is a version tag, and the package is listed once the repository carries the topic `pudu-package`.\n\nCommit and push the project to GitHub, then:\n\n```sh\npudu login\npudu release 1.2.0 --notes CHANGES.md\n```\n\n`pudu login` stores a GitHub token. It takes the one the GitHub CLI already has (`gh auth login`), or one given with `pudu login --token <token>`; CI can set `PUDU_TOKEN` instead. `pudu release` checks the project, runs its tests, tags the commit `v1.2.0`, and pushes the tag — the release exists from that moment. With a token it also creates the GitHub release with your notes and adds the `pudu-package` topic, which is what lists the package in `pudu search` and on the website.\n\n| Command | Does |\n| --- | --- |\n| `pudu release 1.2.0 --notes CHANGES.md` | checks, tests, tags `v1.2.0`, pushes it, and publishes the GitHub release |\n| `pudu search json` | lists packages on GitHub |\n| `pudu logout` | forgets the token on this machine |\n\n`pudu release` refuses a version that is not the one in `pudu.toml` and a working tree with changes not committed. Installing locks the commit the tag named and a digest of its files, so moving or deleting the tag later changes no locked build. A private repository's packages install for anyone git can authenticate to it.\n\n## Choosing new versions\n\n`pudu update` moves to the newest releases the requirements in `pudu.toml` accept, so it never crosses a major version. `pudu upgrade` rewrites each requirement to the newest release and names every package whose major version changed, with the address of its release notes.\n\nA new resolution does not choose a release published in the last 72 hours: most poisoned releases are found and pulled within that time. A version already in `pudu.lock`, or one named exactly (`pudu install @alice/json-schema@1.4.3`), is always allowed. The age is set under `[install]`:\n\n```toml\n[install]\nmin-release-age = 24\n```\n\n## Module roots\n\nEach package owns one module root: `parser` owns `Parser` and every module beneath it. The root is the package's name in PascalCase unless its own `pudu.toml` sets `root`. Two packages in one program may not own the same root, and `pudu install` says which two collide before anything is changed:\n\n```text\npudu install: clash and shapes-kit both own the module root ShapesKit; a program can use only one package for each root\n```\n\n`Std` belongs to the compiler. A package that ships a module under `Std` or `Core` is refused, so no dependency can quietly replace part of the standard library. A project may still shadow a standard module deliberately, in its own `src`, where a reader will see it.\n\n## What installing never does\n\nInstalling a package copies files and checks their digests. It never runs anything the package contains: there are no install scripts, no build hooks, and no compilation step. A dependency can only do something when your program calls it.\n\nOne version of each package is used by the whole program. When two dependencies need versions that cannot both be met, `pudu install` names each requirement and who asked for it, rather than installing two copies whose types would not match.\n"},22  Chapter.Chapter{group: "docs", slug: "traits", title: "Traits and methods", markdown: "# Traits and methods\n\nA trait names behavior that types can provide. An implementation provides it for one type, and generic code can ask for any type that does.\n\n## Declaring and implementing a trait\n\n```pudu\nmodule Animals\n\ntrait Speak \{\n  fn sound(self: &Self) -> Str\n\}\n\ntype Dog = \{ name: Str \}\n\ntype Cat = \{ name: Str \}\n\nimpl Speak for Dog \{\n  fn sound(self: &Self) -> Str \{ \"\{self.name\} says woof\" \}\n\}\n\nimpl Speak for Cat \{\n  fn sound(self: &Self) -> Str \{ \"\{self.name\} says meow\" \}\n\}\n\nfn main() -> Int \{\n  let rex = Dog\{name: \"Rex\"\}\n  if rex.sound() == \"Rex says woof\" \{ 0 \} else \{ 1 \}\n\}\n```\n\nInside an implementation, `Self` is the type being implemented. An implementation must live in the module that declares the trait or the module that declares the type, so two libraries can never provide conflicting implementations of the same pair.\n\n## Where methods come from\n\nA value has methods from exactly two places:\n\n- the built-in methods of `Array`, `Str`, `Map`, `Set`, and `Char`, such as `text.trim()` and `items.length()`;\n- the `impl` blocks a program writes.\n\nEverything else is a module function called with the value as an argument. `Option` is an ordinary sum type that nothing implements methods for, so its helpers read `Option.unwrapOr(value, fallback)`, not `value.unwrapOr(fallback)`.\n\n## Qualified calls\n\nA method can also be called through the type or the trait, with the receiver as the first argument. This is how a program chooses between two traits that both declare a method of the same name for one type:\n\n```pudu\nmodule Qualified\n\ntrait Speak \{\n  fn label(self: &Self) -> Str\n\}\n\ntype Bot = \{ id: Int \}\n\nimpl Speak for Bot \{\n  fn label(self: &Self) -> Str \{ \"bot \{self.id\}\" \}\n\}\n\nfn main() -> Int \{\n  let bot = Bot\{id: 7\}\n  if Speak.label(&bot) == bot.label() \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Generic bounds\n\nA type parameter can require traits, so a generic function can use what those traits promise:\n\n```pudu\nmodule Bounds\n\ntrait Describe \{\n  fn describe(self: &Self) -> Str\n\}\n\ntype Planet = \{ name: Str \}\n\nimpl Describe for Planet \{\n  fn describe(self: &Self) -> Str \{ \"the planet \{self.name\}\" \}\n\}\n\nfn announce[T: Describe](thing: &T) -> Str \{\n  \"Here is \{thing.describe()\}\"\n\}\n\nfn main() -> Int \{\n  if announce(&Planet\{name: \"Mars\"\}) == \"Here is the planet Mars\" \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Mixing types behind a trait\n\n`dynamic Trait` is the type of some value that implements the trait, without naming which type it is. It is what a collection of different implementations needs:\n\n```pudu\nmodule Chorus\n\ntrait Speak \{\n  fn sound(self: &Self) -> Str\n\}\n\ntype Dog = \{ name: Str \}\n\ntype Cat = \{ name: Str \}\n\nimpl Speak for Dog \{\n  fn sound(self: &Self) -> Str \{ \"woof\" \}\n\}\n\nimpl Speak for Cat \{\n  fn sound(self: &Self) -> Str \{ \"meow\" \}\n\}\n\nfn main() -> Int \{\n  let pets: Array[dynamic Speak] = [Dog\{name: \"Rex\"\}, Cat\{name: \"Tom\"\}]\n  var sounds: Array[Str] = []\n  for pet in pets \{\n    sounds = sounds.push(pet.sound())\n  \}\n  if sounds == [\"woof\", \"meow\"] \{ 0 \} else \{ 1 \}\n\}\n```\n\nA concrete value becomes a `dynamic` one wherever that is what the context expects. Going the other way — from a `dynamic` value back to a concrete type — is never automatic.\n"},23  Chapter.Chapter{group: "docs", slug: "generics", title: "Generics", markdown: "# Generics\n\nGeneric code is written once and used with many types. `Array[T]`, `Option[T]`, and `Result[T, E]` are generic, and your own functions and types can be too. This chapter builds on [functions](/docs/functions) and [traits](/docs/traits).\n\n## Type parameters\n\nA type parameter is a name for a type the caller chooses. It is written in square brackets after the function's or the type's name, and the compiler works out what it stands for at every use:\n\n```pudu\nmodule Stacks\n\ntype Stack[T] = \{ items: Array[T] \}\n\nfn empty[T]() -> Stack[T] = Stack\{items: []\}\n\nfn push[T](stack: Stack[T], item: T) -> Stack[T] = Stack\{items: stack.items.push(item)\}\n\nfn peek[T](stack: &Stack[T]) -> Option[T] \{\n  if stack.items.isEmpty() \{ None \} else \{ Some(stack.items[stack.items.length() - 1]) \}\n\}\n\nfn main() -> Int \{\n  let numbers: Stack[Int] = push(push(empty(), 1), 2)\n  let words = push(empty(), \"top\")\n  if peek(&numbers) == Some(2) && peek(&words) == Some(\"top\") \{ 0 \} else \{ 1 \}\n\}\n```\n\n`Stack[Int]` and `Stack[Str]` are different types. A function that takes a `Stack[Int]` does not accept a `Stack[Str]`, and nothing is checked at run time to make that true.\n\n## Several parameters\n\nA declaration can take as many type parameters as it needs:\n\n```pudu\nmodule Pairs\n\ntype Entry[K, V] = \{ key: K, value: V \}\n\nfn entry[K, V](key: K, value: V) -> Entry[K, V] = Entry\{key: key, value: value\}\n\nfn swap[K, V](held: Entry[K, V]) -> Entry[V, K] = Entry\{key: held.value, value: held.key\}\n\nfn main() -> Int \{\n  let age = entry(\"ada\", 36)\n  let flipped = swap(age)\n  if flipped.key == 36 && flipped.value == \"ada\" \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Bounds\n\nA plain type parameter promises nothing about its type, so the function can only move values of it around. A bound asks for a trait, and then the function may use what the trait provides:\n\n```pudu\nmodule Ranking\n\nimport Std.List as List\n\ntrait Scored \{\n  fn score(self: &Self) -> Int\n\}\n\ntype Player = \{ name: Str, points: Int \}\n\ntype Team = \{ name: Str, wins: Int \}\n\nimpl Scored for Player \{\n  fn score(self: &Self) -> Int \{ self.points \}\n\}\n\nimpl Scored for Team \{\n  fn score(self: &Self) -> Int \{ self.wins * 3 \}\n\}\n\nfn best[T: Scored](entrants: &Array[T]) -> Option[T] \{\n  List.maximumOn(entrants, fn(entrant: T) => entrant.score())\n\}\n\nfn main() -> Int \{\n  let players = [Player\{name: \"ada\", points: 12\}, Player\{name: \"grace\", points: 30\}]\n  let teams = [Team\{name: \"red\", wins: 4\}, Team\{name: \"blue\", wins: 7\}]\n  let topPlayer = best(&players)\n  let topTeam = best(&teams)\n  let named = match topPlayer \{ case Some(player) => player.name case None => \"\" \}\n  if named == \"grace\" && topTeam == Some(Team\{name: \"blue\", wins: 7\}) \{ 0 \} else \{ 1 \}\n\}\n```\n\nThe bound is checked where `best` is called: calling it with an array of a type that does not implement `Scored` is a compile error at that call, naming the missing implementation.\n\n## Traits generic code asks for\n\nA few traits appear in almost every generic signature. Three are part of the language and need no import; the comparison traits live in [Std.Order](/module/Std.Order) and are imported like anything else:\n\n| Trait | A type that has it can | Comes from |\n| --- | --- | --- |\n| `Copy` | be copied rather than moved; numbers, `Bool`, and `Char` are | the language |\n| `Send` | be handed to another worker | the language |\n| `Sync` | be shared between workers | the language |\n| `Eq` | be compared for equality | `import Std.Order \{Eq\}` |\n| `Ord` | be ordered and sorted | `import Std.Order \{Ord\}` |\n| `Hash` | be a key in a hash map | `import Std.Order \{Hash\}` |\n\n`List.sorted` is declared with `where T: Ord`, so it sorts numbers and text but refuses a record that has no ordering.\n\n## where clauses\n\nWhen bounds get long, they can move after the signature:\n\n```pudu\nmodule Wheres\n\nimport Std.List as List\nimport Std.Order \{Ord\}\n\nfn middle[T](items: &Array[T]) -> Option[T] where T: Ord \{\n  let ordered = List.sorted(items)\n  if ordered.isEmpty() \{ None \} else \{ Some(ordered[ordered.length() / 2]) \}\n\}\n\nfn main() -> Int \{\n  if middle(&[9, 1, 5]) == Some(5) && middle(&[\"b\", \"c\", \"a\"]) == Some(\"b\") \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Parameters that stand for a container\n\nA type parameter usually stands for a type, like `Int` or `Str`. A parameter written `F[_]` stands for a type that still takes one argument — `Array`, `Option`, or a generic type of the program's own — so one trait can describe every container that can be transformed without changing its shape:\n\n```pudu\nmodule Containers\n\ntrait Container[F[_]] \{\n  fn transformed[A, B](self: &F[A], change: fn(A) -> B) -> F[B]\n\}\n\ntype Pair[T] = \{ left: T, right: T \}\n\nimpl Container[Pair] for Pair \{\n  fn transformed[A, B](self: &Pair[A], change: fn(A) -> B) -> Pair[B] \{\n    Pair\{left: change(self.left), right: change(self.right)\}\n  \}\n\}\n\nimpl Container[Array] for Array \{\n  fn transformed[A, B](self: &Array[A], change: fn(A) -> B) -> Array[B] \{\n    self.map(change)\n  \}\n\}\n\nfn lengths[F[_]](texts: &F[Str]) -> F[Int] where F: Container \{\n  texts.transformed(fn(text: Str) => text.length())\n\}\n\nfn main() -> Int \{\n  let sized = lengths(&Pair\{left: \"pudu\", right: \"deer\"\})\n  let many = lengths(&[\"forest\", \"fern\"])\n  if sized.left == 4 && sized.right == 4 && many == [6, 4] \{ 0 \} else \{ 1 \}\n\}\n```\n\n`F[_]` declares that `F` takes exactly one argument; `F[_, _]` would take two. An implementation names the bare constructor, `impl Container[Pair] for Pair`, and `lengths` then works for anything that implements `Container`, keeping the caller's container: a `Pair` in, a `Pair` out. [Std.Mappable](/module/Std.Mappable) is the standard library's trait of this kind.\n\n## Type aliases\n\nAn alias gives a type a shorter or more meaningful name. It stands for exactly the type it names, and it can take parameters of its own:\n\n```pudu\nmodule Aliases\n\ntype Scores = Map[Str, Int]\n\ntype Labelled[T] = Array[(Str, T)]\n\nfn total(scores: &Scores) -> Int \{\n  var sum = 0\n  for (_, points) in *scores \{\n    sum = sum + points\n  \}\n  sum\n\}\n\nfn labels[T](items: &Labelled[T]) -> Array[Str] \{\n  items.map(fn(pair: (Str, T)) => pair[0])\n\}\n\nfn main() -> Int \{\n  let scores: Scores = mapOf([(\"ada\", 3), (\"grace\", 4)])\n  let tagged: Labelled[Bool] = [(\"done\", true), (\"open\", false)]\n  if total(&scores) == 7 && labels(&tagged) == [\"done\", \"open\"] \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Generic code is checked once\n\nA generic function's body is checked against its bounds, not against each type it is later used with. A body that calls `score()` on a `T` without the `Scored` bound is refused where the function is written, before anything calls it. Instantiating a generic function never produces an error inside its body.\n"},24  Chapter.Chapter{group: "docs", slug: "compile-time", title: "Compile time and macros", markdown: "# Compile time and macros\n\nSome work is better done once, when the program is compiled, than every time it runs. Pudu has two tools for that: compile-time functions, which compute values, and macros, which write code.\n\n## Compile-time functions\n\nA function declared `comptime fn` can be run by the compiler. A constant whose value calls one is computed during compilation, so the running program starts with the answer already in place:\n\n```pudu\nmodule Tables\n\nimport Std.Io as Io\n\ncomptime fn powerOfTwo(exponent: Int) -> Int \{\n  var value = 1\n  for _ in 0..exponent \{\n    value = value * 2\n  \}\n  value\n\}\n\ncomptime fn squares(count: Int) -> Array[Int] \{\n  var found: Array[Int] = []\n  for n in 0..count \{\n    found = found.push(n * n)\n  \}\n  found\n\}\n\nconst BUFFER_SIZE: Int = powerOfTwo(12)\nconst SQUARES: Array[Int] = squares(6)\n\nfn main() -> Int \{\n  let _written = Io.writeLine(\"buffer \{BUFFER_SIZE\}, squares \{SQUARES\}\")\n  if BUFFER_SIZE == 4096 && SQUARES[5] == 25 \{ 0 \} else \{ 1 \}\n\}\n```\n\nA compile-time function is still an ordinary function: `main` may call `powerOfTwo(3)` at run time too. What `comptime` adds is a promise the compiler checks — the function does only work that gives the same answer on every machine, every time.\n\n## What compile-time code may do\n\nCompile-time code computes with numbers, text, booleans, collections, and the program's own types. It may call other `comptime` functions and functions handed to it as values. It may not read files, write output, look at the clock or the environment, draw random numbers, start tasks, or open an `unsafe` region, because none of those give the same answer twice:\n\n```text\nerror[E3025]: comptime function cannot call Io.writeLine\n   = help: declare the callee comptime, or move the call out of compile-time code\n```\n\nCompile-time evaluation also runs under a budget of steps, recursion depth, and memory. A function that never finishes is stopped and reported where it ran past the limit, rather than hanging the compiler.\n\n## Macros\n\nA macro writes code where it is called. Its parameters say what kind of syntax each argument is — an expression, a name, or a block — and its body is ordinary Pudu written in terms of them. A call is spelled with `!`, so a reader can always tell that code is being written for them:\n\n```pudu\nmodule Macros\n\nimport Std.Io as Io\n\nmacro twice(value: expr) = value + value\n\nmacro squared(value: expr) = \{\n  let held = value\n  held * held\n\}\n\nmacro swap(left: ident, right: ident) = \{\n  let held = left\n  left = right\n  right = held\n\}\n\nmacro announced(body: block) = \{\n  let _written = Io.writeLine(\"starting\")\n  body\n\}\n\nfn main() -> Int \{\n  let held = \"mine\"\n  var first = 3\n  var second = 4\n  swap!(first, second)\n  let sum = announced!(\{ first + second \})\n  let _written = Io.writeLine(\"\{twice!(21)\} \{squared!(1 + 2)\} \{first\} \{second\} \{held\}\")\n  if twice!(21) == 42 && squared!(1 + 2) == 9 && first == 4 && sum == 7 && held == \"mine\" \{ 0 \} else \{ 1 \}\n\}\n```\n\n| Parameter kind | Accepts | Example argument |\n| --- | --- | --- |\n| `expr` | any expression | `1 + 2`, `items.length()` |\n| `ident` | one name | `first` |\n| `block` | a braced block | `\{ first + second \}` |\n\nAn argument of the wrong kind is reported at the call. A macro takes exactly the arguments it declares.\n\n## Macros are hygienic\n\n`squared!(1 + 2)` is `9`, not `1 + 2 * 1 + 2`: an `expr` argument is substituted as one expression, so operator precedence never changes what it means. The argument is also evaluated once, because the body binds it to `held` before using it twice.\n\nThe names a macro introduces belong to the macro. `swap!` and `squared!` both declare `held`, and so does `main`; each is renamed at every expansion, so a macro can neither overwrite a caller's variable nor pick one up by accident. That is why `held` in `main` is still `\"mine\"` at the end.\n\nMacros are expanded before names are resolved and types are checked, so the code a macro writes is checked exactly as if it had been typed out by hand. A macro that expands into itself forever is stopped by a depth limit and reported where the expansion began.\n\n## Choosing between them\n\nReach for a `comptime fn` when the thing being made is a value: a lookup table, a size, a parsed constant. Reach for a macro when the thing being made is code: a pattern of statements repeated around different expressions. Most programs need neither; an ordinary function is the first tool, and both of these are for when it is not enough.\n"},25  Chapter.Chapter{group: "docs", slug: "testing", title: "Testing", markdown: "# Testing\n\nTests in Pudu are ordinary programs. A test module builds a suite of checks with `Std.Test`, runs it, and reports; `pudu test` finds those modules and runs them. There is no separate test language to learn.\n\n## A first test\n\n```pudu\nmodule PriceTest\n\nimport Std.Test as Test\n\nfn withTax(price: Int, percent: Int) -> Int = price + price * percent / 100\n\nexport fn main() -> Int \{\n  let suite = Test.suite(\"prices\", &[\n      Test.equals(\"adds the tax\", &withTax(200, 10), &220),\n      Test.equals(\"no tax changes nothing\", &withTax(200, 0), &200),\n      Test.that(\"tax never lowers a price\", withTax(50, 5) >= 50)\n    ])\n  Test.report(&Test.run(&suite))\n\}\n```\n\nRun it with `pudu test PriceTest.pudu`, or run every test under a directory with `pudu test test`. The report counts the checks that held, and a failing check prints its name with what it expected and what it found. `Test.report` answers the program's exit status, which is `0` only when every check held.\n\n## Kinds of check\n\n| Check | Holds when |\n| --- | --- |\n| `Test.that(name, condition)` | the condition is true |\n| `Test.not(name, condition)` | the condition is false |\n| `Test.equals(name, &actual, &expected)` | the two values are equal |\n| `Test.differs(name, &left, &right)` | the two values differ |\n| `Test.contains(name, &items, value)` | an array contains the value |\n| `Test.sameElements(name, &left, &right)` | two arrays hold the same values in any order |\n| `Test.succeeded(name, &result)` | a `Result` is `Ok` |\n| `Test.errored(name, &result)` | a `Result` is `Err` |\n| `Test.present(name, &option)` | an `Option` is `Some` |\n| `Test.absent(name, &option)` | an `Option` is `None` |\n| `Test.todo(name, reason)` | never: it marks a check still to be written |\n\nPrefer `equals` to `that(name, a == b)`: when it fails, it shows both values rather than only `false`.\n\n## Testing failure\n\nCode that returns a `Result` is tested on both paths:\n\n```pudu\nmodule ParseTest\n\nimport Std.Test as Test\nimport Std.Text as Text\n\nfn parseAge(text: Str) -> Result[Int, Str] \{\n  match Text.wholeOf(text.trim()) \{\n    case Some(age) if age >= 0 && age < 150 => Ok(age)\n    case Some(_) => Err(\"out of range\")\n    case None => Err(\"not a number\")\n  \}\n\}\n\nexport fn main() -> Int \{\n  let suite = Test.suite(\"ages\", &[\n      Test.equals(\"reads a number\", &parseAge(\" 36 \"), &Ok(36)),\n      Test.errored(\"refuses text\", &parseAge(\"thirty\")),\n      Test.equals(\"says why\", &parseAge(\"400\"), &Err(\"out of range\"))\n    ])\n  Test.report(&Test.run(&suite))\n\}\n```\n\n## Tables of cases\n\nWhen one check applies to many inputs, write the inputs as data. `Test.each` builds one check per case, named from the case:\n\n```pudu\nmodule LeapTest\n\nimport Std.Test as Test\n\nfn isLeap(year: Int) -> Bool \{\n  (year % 4 == 0 && year % 100 != 0) || year % 400 == 0\n\}\n\nexport fn main() -> Int \{\n  let leap = [1996, 2000, 2024]\n  let common = [1900, 2023, 2100]\n  let leapChecks = Test.each(&leap, fn(year: Int) => \"\{year\} is leap\", isLeap)\n  let commonChecks = Test.each(&common, fn(year: Int) => \"\{year\} is not leap\", fn(year: Int) => !isLeap(year))\n  let suite = Test.suite(\"leap years\", &leapChecks.concat(commonChecks))\n  Test.report(&Test.run(&suite))\n\}\n```\n\n## Groups\n\nSuites nest. A group gathers suites under a name, and the report counts through every level:\n\n```pudu\nmodule ShopTest\n\nimport Std.Test as Test\n\nfn discount(total: Int) -> Int = if total >= 100 \{ total / 10 \} else \{ 0 \}\n\nexport fn main() -> Int \{\n  let small = Test.suite(\"small orders\", &[Test.equals(\"no discount\", &discount(99), &0)])\n  let large = Test.suite(\"large orders\", &[\n      Test.equals(\"ten percent\", &discount(100), &10),\n      Test.equals(\"scales\", &discount(250), &25)\n    ])\n  let everything = Test.group(\"shop\", &[small, large])\n  Test.report(&Test.run(&everything))\n\}\n```\n\n## Property checks\n\nA property check states something that should hold for every input, and tries it on many generated ones. When it finds an input that breaks the property, it looks for a simpler one before reporting:\n\n```pudu\nmodule PropertyTest\n\nimport Std.Test as Test\nimport Std.Test.Property as Property\n\nfn reverse(items: Array[Int]) -> Array[Int] \{\n  var reversed: Array[Int] = []\n  for item in items \{\n    reversed = [item].concat(reversed)\n  \}\n  reversed\n\}\n\nexport fn main() -> Int \{\n  let suite = Test.suite(\"properties\", &[\n      Property.forAllInts(\"doubling is adding a number to itself\", 42u64, 200, 1000, fn(n: Int) => n * 2 == n + n),\n      Property.forAllInts(\"absolute values are never negative\", 7u64, 200, 1000, fn(n: Int) => (if n < 0 \{ -n \} else \{ n \}) >= 0),\n      Test.equals(\"reversing twice gives the original\", &reverse(reverse([1, 2, 3])), &[1, 2, 3])\n    ])\n  Test.report(&Test.run(&suite))\n\}\n```\n\n`forAllInts` takes a name, a seed so a failure can be reproduced exactly, how many values to try, and the bound the values stay below.\n\n## Where tests live\n\n`pudu init` puts tests under `test/`, mirroring the modules they test: `src/App/Greeting.pudu` is tested by `test/App/GreetingTest.pudu`. `pudu test` with no path runs everything under `test/`.\n\nKeep most logic in modules that take values and return values, and most tests there too. Code that reads files or the network is tested best by passing it the data it would have read, rather than by reaching the outside world from a test.\n"},26  Chapter.Chapter{group: "docs", slug: "files", title: "Files and the system", markdown: "# Files and the system\n\nPrograms read files, write output, and ask the machine questions. In Pudu every one of those can fail, so every one returns a `Result`, and nothing reaches the outside world except through a standard library call you can see.\n\n## Output\n\n`Std.Io` writes to the program's standard output and error output:\n\n```pudu\nmodule Report\n\nimport Std.Io as Io\n\nfn main() -> Int \{\n  let lines = [\"name   score\", \"ada       95\", \"grace    100\"]\n  match Io.writeLines(&lines) \{\n    case Ok(_) => 0\n    case Err(problem) => \{\n      let _reported = Io.writeErrorLine(\"could not write the report: \{problem\}\")\n      1\n    \}\n  \}\n\}\n```\n\n| Function | Writes |\n| --- | --- |\n| `Io.writeLine(text)` | one line to standard output |\n| `Io.writeLines(&lines)` | several lines, stopping at the first failure |\n| `Io.writeErrorLine(text)` | one line to standard error |\n| `Io.writeValue(value)` | any value, rendered as text |\n\n## Reading and writing files\n\nA whole file is read with `Io.read` and written with `Io.write`. Both use plain text paths and answer a `Result` whose error says what went wrong:\n\n```pudu\nmodule Notes\n\nimport Std.Env as Env\nimport Std.Io as Io\n\nfn keepNotes(path: Str) -> Result[Int, Str] \{\n  Io.write(path, \"first note\\n\") ?\n  Io.appendLine(path, \"second note\") ?\n  let lines = Io.readLines(path) ?\n  let text = Io.read(path) ?\n  Io.remove(path) ?\n  if text.contains(\"second\") \{ Ok(lines.length()) \} else \{ Err(\"the note was not kept\") \}\n\}\n\nfn main() -> Int \{\n  let path = Io.join(Env.temporaryDirectory(), \"pudu-notes-example.txt\")\n  match keepNotes(path) \{\n    case Ok(count) => if count == 2 && !Io.exists(path) \{ 0 \} else \{ 1 \}\n    case Err(_) => 1\n  \}\n\}\n```\n\nBecause every call answers a `Result`, `?` gives a function a straight line through the steps that stops at the first one that fails.\n\n## Large files\n\n`Io.read` holds a whole file in memory. For a file that may be large, fold over it one line at a time instead; only the current chunk is ever held:\n\n```pudu\nmodule Totals\n\nimport Std.Env as Env\nimport Std.Io as Io\nimport Std.Option as Option\nimport Std.Text as Text\n\nfn main() -> Int \{\n  let path = Io.join(Env.temporaryDirectory(), \"pudu-totals-example.txt\")\n  let prepared = Io.writeFileLines(path, &[\"10\", \"20\", \"not a number\", \"12\"])\n  if prepared != Ok(()) \{ return 1 \}\n  let summed = Io.foldLines(path, 0, fn(total: Int, line: Str) => total + Option.unwrapOr(Text.wholeOf(line), 0))\n  let _removed = Io.remove(path)\n  if summed == Ok(42) \{ 0 \} else \{ 1 \}\n\}\n```\n\n`Io.forEachLine` does the same when there is nothing to accumulate, and `Std.Json.foldLines` and `Std.Csv.foldRows` read structured files the same way.\n\n## Paths\n\n`Std.Path` builds and takes apart paths without touching the filesystem:\n\n```pudu\nmodule Paths\n\nimport Std.Path as Path\n\nfn main() -> Int \{\n  let report = Path.joinAll(&[\"reports\", \"2026\", \"summary.csv\"])\n  let checks = [\n    Path.nameOf(report) == \"summary.csv\",\n    Path.stemOf(report) == \"summary\",\n    Path.extensionOf(report) == Some(\"csv\"),\n    Path.withExtension(report, \"json\").endsWith(\"summary.json\"),\n    Path.normalize(\"reports/./2026/../2027\") == Path.join(\"reports\", \"2027\")\n  ]\n  if checks.filter(fn(held: Bool) => !held).isEmpty() \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Directories\n\n| Function | Does |\n| --- | --- |\n| `Io.list(directory)` | the names a directory holds |\n| `Io.listPaths(directory)` | the same names, joined to the directory |\n| `Io.makeDirectory(path)` | creates a directory and any parents it needs |\n| `Io.exists(path)` | whether something is there |\n| `Fs.metadata(path)` | size, kind, and permissions |\n| `Fs.removeTree(path)` | removes a directory and everything under it |\n| `Fs.writeTextAtomically(path, text)` | replaces a file so no reader ever sees it half written |\n\n## The environment\n\n`Std.Env` answers questions about how the program was started:\n\n```pudu\nmodule Settings\n\nimport Std.Env as Env\nimport Std.Option as Option\nimport Std.Text as Text\n\nfn portSetting() -> Int \{\n  let written = Env.variableOr(\"PUDU_EXAMPLE_PORT\", \"8080\")\n  Option.unwrapOr(Text.wholeOf(written), 8080)\n\}\n\nfn main() -> Int \{\n  let verbose = Env.hasFlag(\"--verbose\")\n  let started = Env.elapsedMilliseconds()\n  if portSetting() > 0 && (verbose || !verbose) && started >= 0 \{ 0 \} else \{ 1 \}\n\}\n```\n\n| Function | Answers |\n| --- | --- |\n| `Env.all()` | every argument |\n| `Env.at(position)` | one argument, or `None` |\n| `Env.hasFlag(flag)` | whether an exact argument was given |\n| `Env.option(name)` | the value after a named argument, as in `--port 80` |\n| `Env.variable(name)` | an environment variable, or `None` |\n| `Env.variableOr(name, fallback)` | an environment variable, or a fallback |\n\nFor a program with many options, [Std.Args](/module/Std.Args) declares them, checks them, and writes the help text.\n\n## Other programs\n\n[Std.Process](/module/Std.Process) starts other programs, writes to their input, and reads their output, with the same `Result` on every step.\n"},27  Chapter.Chapter{group: "docs", slug: "data-formats", title: "Data formats", markdown: "# Data formats\n\nPrograms exchange data as text: JSON between services, CSV from spreadsheets, TOML in configuration files. The standard library reads each into ordinary Pudu values and writes them back, and a malformed document is always a `Result` you handle rather than a crash.\n\n## JSON\n\nA JSON document is a `Json` value, a sum type with one variant for each kind of JSON value:\n\n| Variant | JSON |\n| --- | --- |\n| `Null` | `null` |\n| `Boolean(Bool)` | `true`, `false` |\n| `Number(Int)` | a whole number |\n| `Fractional(Str)` | a number with a fraction, kept as its exact text |\n| `Text(Str)` | a string |\n| `List(Array[Json])` | an array |\n| `Object(Array[(Str, Json)])` | an object, with its keys in the order they were written |\n\n### Reading\n\n`Json.decode` reads text. The accessors each answer an `Option`, because the value might not be the kind asked for:\n\n```pudu\nmodule ReadJson\n\nimport Std.Json as Json\nimport Std.Option as Option\n\ntype User = \{ name: Str, age: Int, admin: Bool \}\n\nfn userFrom(value: &Json.Json) -> Option[User] \{\n  let name = Json.asText(&Json.field(value, \"name\") ?) ?\n  let age = Json.asInt(&Json.field(value, \"age\") ?) ?\n  let admin = Option.unwrapOr(Option.andThen(Json.field(value, \"admin\"), fn(held: Json.Json) -> Option[Bool] \{ Json.asBool(&held) \}), false)\n  Some(User\{name: name, age: age, admin: admin\})\n\}\n\nfn main() -> Int \{\n  let text = \"\\\{\\\"name\\\": \\\"Ada\\\", \\\"age\\\": 36, \\\"languages\\\": [\\\"English\\\", \\\"French\\\"]\\\}\"\n  let value = match Json.decode(text) \{\n    case Ok(held) => held\n    case Err(problem) => \{ return 1 \}\n  \}\n  let languages = Option.unwrapOr(Option.andThen(Json.field(&value, \"languages\"), fn(held: Json.Json) -> Option[Array[Json.Json]] \{ Json.asList(&held) \}), [])\n  match userFrom(&value) \{\n    case Some(user) => if user.name == \"Ada\" && user.age == 36 && !user.admin && languages.length() == 2 \{ 0 \} else \{ 1 \}\n    case None => 1\n  \}\n\}\n```\n\n`userFrom` uses `?` on each `Option`: if any field is missing or has the wrong kind, the whole function answers `None`. When a document does not decode, `Json.explain(&problem)` describes where and why in words a person can act on.\n\n### Writing\n\nA value is built with `Json.object` and `Json.list`, then written compactly with `Json.encode` or across lines with `Json.encodePretty`:\n\n```pudu\nmodule WriteJson\n\nimport Std.Json as Json\n\ntype Task = \{ title: Str, done: Bool, estimate: Int \}\n\nfn taskJson(item: Task) -> Json.Json \{\n  Json.object(&[\n      (\"title\", Json.Text(item.title)),\n      (\"done\", Json.Boolean(item.done)),\n      (\"estimate\", Json.Number(item.estimate))\n    ])\n\}\n\nfn main() -> Int \{\n  let tasks = [Task\{title: \"write\", done: true, estimate: 3\}, Task\{title: \"review\", done: false, estimate: 1\}]\n  let document = Json.object(&[(\"tasks\", Json.list(&tasks.map(taskJson)))])\n  let compact = Json.encode(&document)\n  let readBack = Json.decode(compact)\n  if compact.startsWith(\"\\\{\\\"tasks\\\":[\\\{\\\"title\\\":\\\"write\\\"\") && readBack == Ok(document) \{ 0 \} else \{ 1 \}\n\}\n```\n\nText is escaped on the way out, and reading what was written gives back an equal value.\n\n## CSV\n\n`Csv.parseTable` reads CSV whose first row names the columns. A row can then be read by column name:\n\n```pudu\nmodule Spreadsheet\n\nimport Std.Csv as Csv\nimport Std.Map as Map\nimport Std.Option as Option\nimport Std.Text as Text\n\nfn main() -> Int \{\n  let text = \"name,team,points\\nada,red,12\\ngrace,blue,30\\n\\\"lin, jr\\\",red,8\\n\"\n  let table = match Csv.parseTable(text) \{\n    case Ok(held) => held\n    case Err(_) => \{ return 1 \}\n  \}\n  var redPoints = 0\n  for row in Csv.records(&table) \{\n    if Map.getOr(&row, \"team\", \"\") == \"red\" \{\n      redPoints = redPoints + Option.unwrapOr(Text.wholeOf(Map.getOr(&row, \"points\", \"0\")), 0)\n    \}\n  \}\n  let names = Option.unwrapOr(Csv.column(&table, \"name\"), [])\n  let written = Csv.render(&[[\"name\", \"note\"], [\"ada\", \"said \\\"hello\\\"\"]])\n  if redPoints == 20 && names[2] == \"lin, jr\" && written.contains(\"\\\"said \\\"\\\"hello\\\"\\\"\\\"\") \{ 0 \} else \{ 1 \}\n\}\n```\n\nQuoted fields, commas inside quotes, and doubled quotes are handled in both directions. For a file too large to hold, `Csv.foldRows(path, start, step)` reads it one row at a time.\n\n## TOML\n\nConfiguration is usually TOML. `Std.Toml.Read.read` parses a document, and `Toml.path` walks dotted keys:\n\n```pudu\nmodule Configuration\n\nimport Std.Option as Option\nimport Std.Toml as Toml\nimport Std.Toml.Read as TomlRead\n\ntype Settings = \{ host: Str, port: Int, debug: Bool \}\n\nfn settingsFrom(document: &Toml.Toml) -> Settings \{\n  let host = Option.unwrapOr(Option.andThen(Toml.path(document, \"server.host\"), fn(held: Toml.Toml) -> Option[Str] \{ Toml.asText(&held) \}), \"127.0.0.1\")\n  let port = Option.unwrapOr(Option.andThen(Toml.path(document, \"server.port\"), fn(held: Toml.Toml) -> Option[Int] \{ Toml.asWhole(&held) \}), 8080)\n  let debug = Option.unwrapOr(Option.andThen(Toml.path(document, \"debug\"), fn(held: Toml.Toml) -> Option[Bool] \{ Toml.asBoolean(&held) \}), false)\n  Settings\{host: host, port: port, debug: debug\}\n\}\n\nfn main() -> Int \{\n  let text = \"debug = true\\n\\n[server]\\nhost = \\\"0.0.0.0\\\"\\nport = 9000\\n\"\n  match TomlRead.read(text) \{\n    case Ok(document) => \{\n      let settings = settingsFrom(&document)\n      if settings.host == \"0.0.0.0\" && settings.port == 9000 && settings.debug \{ 0 \} else \{ 1 \}\n    \}\n    case Err(_) => 1\n  \}\n\}\n```\n\nEvery setting in `settingsFrom` has a default, so a configuration file only needs to name what it changes.\n\n## More formats\n\n| Module | Reads and writes |\n| --- | --- |\n| [Std.Yaml](/module/Std.Yaml) | YAML documents |\n| [Std.Xml](/module/Std.Xml) | XML documents and their attributes |\n| [Std.Bytes](/module/Std.Bytes) | hex and base64 |\n| [Std.Archive.Zip](/module/Std.Archive.Zip) and [Std.Archive.Tar](/module/Std.Archive.Tar) | archives |\n| [Std.Compress.Gzip](/module/Std.Compress.Gzip) | gzip compression |\n"},28  Chapter.Chapter{group: "docs", slug: "http", title: "HTTP servers and clients", markdown: "# HTTP servers and clients\n\n`Std.Http.Server` answers HTTP requests and `Std.Http.Client` makes them. A server is built from values — routes, a router, handlers — so most of it can be written and tested without opening a socket.\n\n## Handlers and routes\n\nA handler is a function from a request to a response. A route pairs a method and a path pattern with a handler, and a router holds the routes:\n\n```pudu\nmodule Greeter\n\nimport Std.Http as Http\nimport Std.Http.Server.Reply as Reply\nimport Std.Http.Server.Route as Route\nimport Std.Option as Option\n\nfn hello(request: Route.Request) -> Http.Response \{\n  let name = Option.unwrapOr(Route.queryParam(&request, \"name\"), \"world\")\n  Reply.text(200, \"Hello, \{name\}!\")\n\}\n\nfn user(request: Route.Request) -> Http.Response \{\n  match Route.param(&request, \"id\") \{\n    case Some(id) => Reply.text(200, \"user \{id\}\")\n    case None => Reply.text(400, \"no user\")\n  \}\n\}\n\nfn routes() -> Route.Router \{\n  Route.routing(&[\n      Route.get(\"/hello\", hello),\n      Route.get(\"/users/:id\", user)\n    ])\n\}\n\nfn ask(router: &Route.Router, target: Str) -> Http.Response \{\n  let request = Route.Request\{\n    message: Http.Request\{method: Http.Get, target: target, headers: [], body: \"\", binaryBody: None\},\n    path: Route.pathOf(target),\n    params: mapOf([]),\n    query: Route.queryOf(target),\n    peer: \"example\"\n  \}\n  Route.dispatch(router, request)\n\}\n\nfn main() -> Int \{\n  let router = routes()\n  let greeted = ask(&router, \"/hello?name=Ada\")\n  let found = ask(&router, \"/users/7\")\n  let missing = ask(&router, \"/nowhere\")\n  let ok = greeted.body == \"Hello, Ada!\" && found.body == \"user 7\"\n  if ok && missing.status.code == 404 \{ 0 \} else \{ 1 \}\n\}\n```\n\n`:id` in a pattern captures one piece of the path, read with `Route.param`. `Route.queryParam` reads the query string. A request nothing matches is answered `404`.\n\nBecause a router is a value and `Route.dispatch` is a function, the `ask` helper above is all a test needs: no port, no network, and no waiting.\n\n## Replies\n\n`Std.Http.Server.Reply` builds the common responses:\n\n| Reply | Answers |\n| --- | --- |\n| `Reply.text(status, text)` | plain text |\n| `Reply.html(status, html)` | an HTML page from text |\n| `Reply.page(status, document)` | a page built with `Std.Html`, escaped by construction |\n| `Reply.json(status, encoded)` | JSON that is already text |\n| `Reply.jsonValue(status, value)` | a `Std.Json` value, encoded |\n| `Reply.empty(status)` | a status and nothing else |\n| `Reply.unprocessable(reason)` | `422`, for a body that could not be acted on |\n\n## A JSON API\n\nA handler reads the body with `Route.body`, decodes it, and answers:\n\n```pudu\nmodule Api\n\nimport Std.Http as Http\nimport Std.Http.Server.Reply as Reply\nimport Std.Http.Server.Route as Route\nimport Std.Json as Json\nimport Std.Option as Option\n\nfn create(request: Route.Request) -> Http.Response \{\n  let decoded = Json.decode(Route.body(&request))\n  let value = match decoded \{\n    case Ok(held) => held\n    case Err(_) => \{ return Reply.text(400, \"the body is not JSON\") \}\n  \}\n  let title = Option.andThen(Json.field(&value, \"title\"), fn(held: Json.Json) -> Option[Str] \{ Json.asText(&held) \})\n  match title \{\n    case Some(text) if !text.trim().isEmpty() =>\n      Reply.jsonValue(201, Json.object(&[(\"title\", Json.Text(text)), (\"done\", Json.Boolean(false))]))\n    case _ => Reply.unprocessable(\"title must be non-empty text\")\n  \}\n\}\n\nfn post(router: &Route.Router, body: Str) -> Http.Response \{\n  let request = Route.Request\{\n    message: Http.Request\{method: Http.Post, target: \"/tasks\", headers: [], body: body, binaryBody: None\},\n    path: \"/tasks\",\n    params: mapOf([]),\n    query: mapOf([]),\n    peer: \"example\"\n  \}\n  Route.dispatch(router, request)\n\}\n\nfn main() -> Int \{\n  let router = Route.routing(&[Route.post(\"/tasks\", create)])\n  let made = post(&router, \"\\\{\\\"title\\\": \\\"write the docs\\\"\\\}\")\n  let refused = post(&router, \"\\\{\\\"title\\\": \\\"\\\"\\\}\")\n  let broken = post(&router, \"not json\")\n  let ok = made.status.code == 201 && made.body.contains(\"write the docs\")\n  if ok && refused.status.code == 422 && broken.status.code == 400 \{ 0 \} else \{ 1 \}\n\}\n```\n\n## Serving\n\n`Std.Http.Server` turns a router into a server and listens. `listenAndServe` takes the host, the port, and how many connections to serve before stopping, where `0` means no limit:\n\n```pudu\nmodule Serve\n\nimport Std.Env as Env\nimport Std.Http as Http\nimport Std.Http.Server as Server\nimport Std.Http.Server.Reply as Reply\nimport Std.Http.Server.Route as Route\nimport Std.Io as Io\n\nfn home(_request: Route.Request) -> Http.Response \{\n  Reply.text(200, \"Served by Pudu\")\n\}\n\nexport fn main() -> Int \{\n  let router = Route.routing(&[Route.get(\"/\", home)])\n  let server = Server.server(&router)\n  if !Env.hasFlag(\"--serve\") \{\n    let _written = Io.writeLine(\"run with --serve to listen on http://127.0.0.1:8080\")\n    return 0\n  \}\n  match Server.listenAndServe(&server, \"127.0.0.1\", 8080, 0) \{\n    case Ok(_) => 0\n    case Err(_) => 1\n  \}\n\}\n```\n\nThe server reads requests with limits on their size and on how long they may take, runs a fixed pool of workers, and stops cleanly when the program is asked to stop. [Std.App](/module/Std.App) builds on it with configuration, health checks, and graceful shutdown for a complete service.\n\n## Making requests\n\n`Std.Http.Client` fetches a URL within limits on size, time, and redirects. Verified TLS is used for `https`:\n\n```pudu\nmodule Fetch\n\nimport Std.Env as Env\nimport Std.Http.Client as Client\nimport Std.Io as Io\n\nexport fn main() -> Int \{\n  if !Env.hasFlag(\"--fetch\") \{\n    let _written = Io.writeLine(\"run with --fetch to request https://example.com\")\n    return 0\n  \}\n  match Client.fetch(\"https://example.com\", &Client.limits()) \{\n    case Ok(response) => \{\n      let _written = Io.writeLine(\"status \{response.status.code\}, \{response.body.length()\} characters\")\n      0\n    \}\n    case Err(problem) => \{\n      let _written = Io.writeErrorLine(Client.explain(&problem))\n      1\n    \}\n  \}\n\}\n```\n\nA failed request is a value: the network being down, a timeout, and a response larger than the limit each arrive as a `ClientError` the program decides what to do with.\n"},29  Chapter.Chapter{group: "docs", slug: "concurrency", title: "Concurrency", markdown: "# Concurrency\n\nPudu has two tools for work that happens alongside other work: asynchronous functions joined by structured scopes, and host workers that run in parallel and talk over channels.\n\n## Async functions\n\nAn `async fn` returns a task. `.await` runs the task and gives its value, and it is allowed only inside another `async fn`. A program that awaits declares `main` itself `async`:\n\n```pudu\nmodule Tasks\n\nimport Std.Io as Io\n\nasync fn scoreFor(name: Str) -> Result[Int, Str] \{\n  if name.isEmpty() \{ Err(\"no name\") \} else \{ Ok(name.length() * 10) \}\n\}\n\nexport async fn main() -> Result[Int, Str] \{\n  let first = scoreFor(\"ada\").await\n  let second = scoreFor(\"grace\").await\n  let _written = Io.writeLine(\"total \{first + second\}\")\n  Ok(0)\n\}\n```\n\nWhen an async function's declared result is `Result[T, E]`, awaiting it gives the `T`. A failure leaves the enclosing function through its own `Result`, so there is no error to unwrap at each `await`.\n\n## Structured scopes\n\n`async with scope \{ ... \}` opens a region that the tasks started inside it cannot outlive. A child that is never awaited is joined when the scope ends, and leaving the scope early — by `return` or `break` — joins the children first. No task is ever left running after the code that started it has finished.\n\n> The interpreter runs async tasks deterministically, one after another. Cancellation and parallel execution of async tasks are not implemented yet.\n\n## Workers and channels\n\nFor work that should run in parallel, `Std.Concurrent` starts host workers and joins them, and `Std.Channel` carries values between them. A channel has a fixed capacity, so a sender that outpaces its receiver waits rather than filling memory. `Std.Sync` provides mutexes and cells for state that workers share.\n\n| Module | Provides |\n| --- | --- |\n| [Std.Concurrent](/module/Std.Concurrent) | starting workers, joining them, bounded parallel maps |\n| [Std.Channel](/module/Std.Channel) | bounded channels between workers |\n| [Std.Sync](/module/Std.Sync) | mutexes and shared cells |\n\nWorker ownership by lexical scopes and cancellation that propagates between workers are not complete yet; join every worker a program starts.\n"},30  Chapter.Chapter{group: "docs", slug: "foreign-code", title: "Unsafe and foreign code", markdown: "# Unsafe and foreign code\n\nEverything on the other pages is checked by the compiler. Some work cannot be: calling a library written in C, or relying on a promise the types do not express. Pudu keeps that work inside regions marked `unsafe`, and makes each one say which kind of trust it is asking for.\n\n## Unsafe regions\n\nAn `unsafe` region names the capabilities it grants:\n\n| Capability | Grants |\n| --- | --- |\n| `foreign` | calling a function declared in a `foreign` block |\n| `raw` | calling functions that work with memory the compiler cannot see |\n| `unchecked` | operations that skip a check the caller has already made |\n| `null` | the `null` value a foreign library may hand back |\n\n`unsafe(foreign) \{ ... \}` grants only foreign calls. `unsafe \{ ... \}` with no list grants all four, and is best kept for code that really needs them. A region that grants a capability nothing inside it used is reported with a warning, so the marked surface stays as small as the work it covers.\n\nUnsafe does not turn anything else off. Inside a region the compiler still checks types, names, ownership, and initialisation; what it grants is the right to make a call whose contract the compiler cannot prove.\n\n## Unsafe functions\n\nA function can be declared unsafe when calling it correctly depends on something its caller must guarantee. The capability it names is then required at every call:\n\n```pudu\nmodule Contracts\n\n/// Reads the item at `index`. The caller has already checked that the index\n/// is in range; this function trusts it.\nunsafe(unchecked) fn itemAt(items: &Array[Int], index: Int) -> Int \{\n  items[index]\n\}\n\n/// The safe wrapper: it makes the check, so its own callers need no region.\nfn itemOr(items: &Array[Int], index: Int, fallback: Int) -> Int \{\n  if index < 0 || index >= items.length() \{ return fallback \}\n  unsafe(unchecked) \{ itemAt(items, index) \}\n\}\n\nfn main() -> Int \{\n  let items = [10, 20, 30]\n  if itemOr(&items, 1, 0) == 20 && itemOr(&items, 9, -1) == -1 \{ 0 \} else \{ 1 \}\n\}\n```\n\nCalling `itemAt` outside a region, or inside one that does not grant `unchecked`, is error `E3023`, and the message names the missing capability. This is the shape unsafe code should take: a small unsafe function with its contract written beside it, and a safe function around it that upholds the contract, so the rest of the program never sees the region.\n\n## Calling a C library\n\nA `foreign` block declares functions another library provides, with the exact types each argument and result crosses as. The library is named first; `\"c\"` is the C library every program already has:\n\n```pudu\nmodule Native\n\nforeign \"c\" version \"1\" \{\n  fn strlen(text: Str) -> Int64\n  fn absolute symbol \"abs\" (value: Int32) -> Int32\n  fn sqrt(value: Float64) -> Float64\n\}\n\nfn byteLength(text: Str) -> Int64 \{\n  unsafe(foreign) \{ strlen(text) \}\n\}\n\nfn main() -> Int \{\n  let ok = unsafe(foreign) \{ absolute(-42i32) == 42i32 && sqrt(144.0) == 12.0 \}\n  if ok && byteLength(\"pudu\") == 4i64 \{ 0 \} else \{ 1 \}\n\}\n```\n\n- `symbol \"abs\"` calls the library's `abs` under a Pudu name, when the library's name is unclear or clashes with one of the program's.\n- Integer widths are part of the declaration. `Int32` and `Int64` are different functions in C, and the width written is the width that crosses.\n- `Str` crosses as UTF-8 text ending in a nought byte, copied for the call. Text coming back that is not valid UTF-8 is refused at the boundary rather than passed on.\n- `version \"1\"` names the library version the declarations were written against.\n\nEvery call to a foreign function needs `unsafe(foreign)`, because the declaration is a claim about the library the compiler cannot check: a wrong signature corrupts the program rather than producing a diagnostic.\n\n## Handles a library owns\n\nMany C libraries hand back a pointer to something they made and expect it to be given back to be freed. A `foreign` block declares such a thing as an opaque type, and names the function that releases it:\n\n```text\nforeign \"imaging\" version \"2\" \{\n  type Image\n  fn open(path: Str) -> owned Image by close\n  fn width(image: Image) -> Int32\n  fn close(image: Image) -> ()\n\}\n```\n\n`owned Image by close` tells Pudu the result belongs to the program and must be released with `close`. A library that answers `NULL` instead of an image, a use after `close`, and a second `close` are each refused before the next foreign call begins, instead of becoming a crash somewhere later.\n\nA library that writes its result through a pointer the caller provides declares that parameter `out`. The call then answers a tuple: the function's own result first, followed by each value written.\n\n## Where foreign code runs\n\nForeign calls are refused in the [playground](/playground), which runs programs confined, and in any program run with `pudu run --confined`. They run everywhere else a Pudu program does. C++ libraries are reached through an `extern \"C\"` surface; C++ names, classes, and exceptions do not cross.\n"},31  Chapter.Chapter{group: "docs", slug: "standard-library", title: "Standard library", markdown: "# Standard library\n\nThe standard library ships with the compiler. Every module lives under `Std`, nothing is imported implicitly, and a program imports exactly what it uses. This page is a map; the [API reference](/modules) documents every public declaration.\n\n## Core values\n\n| Module | For |\n| --- | --- |\n| [Std.Option](/module/Std.Option) | working with values that may be absent |\n| [Std.Result](/module/Std.Result) | working with work that may fail |\n| [Std.Text](/module/Std.Text) | text: searching, splitting, numbers from text |\n| [Std.Char](/module/Std.Char) | single characters |\n| [Std.Math](/module/Std.Math) | numeric functions |\n| [Std.Decimal](/module/Std.Decimal) | exact decimal arithmetic and rounding |\n| [Std.Num](/module/Std.Num), [Std.Bits](/module/Std.Bits) | numeric traits, conversion through `BigInt`, and bitwise work |\n| [Std.Random](/module/Std.Random) | seeded and clock-driven random numbers |\n| [Std.Fmt](/module/Std.Fmt) | formatting values as text |\n\n## Collections\n\n| Module | For |\n| --- | --- |\n| [Std.List](/module/Std.List) | operations on arrays: sorting, grouping, searching |\n| [Std.Map](/module/Std.Map) | ordered maps |\n| [Std.Set](/module/Std.Set) | ordered sets |\n| [Std.Iter](/module/Std.Iter) | sequences a `for` loop can walk |\n| [Std.Deque](/module/Std.Deque), [Std.Heap](/module/Std.Heap) | queues and priority queues |\n\n## Input, output, and the system\n\n| Module | For |\n| --- | --- |\n| [Std.Io](/module/Std.Io) | standard input and output, files, streaming readers |\n| [Std.Fs](/module/Std.Fs) | atomic writes, temporary files, permissions, metadata |\n| [Std.Path](/module/Std.Path) | building and taking apart file paths |\n| [Std.Env](/module/Std.Env) | arguments, environment variables, the clock |\n| [Std.Process](/module/Std.Process) | starting other programs and talking to them |\n| [Std.Time](/module/Std.Time) | dates, times, and durations |\n\n## Data formats\n\n| Module | For |\n| --- | --- |\n| [Std.Json](/module/Std.Json) | JSON documents and JSON Lines |\n| [Std.Csv](/module/Std.Csv) | CSV, read one record at a time |\n| [Std.Toml](/module/Std.Toml), [Std.Yaml](/module/Std.Yaml), [Std.Xml](/module/Std.Xml) | configuration and document formats |\n| [Std.Regex](/module/Std.Regex) | regular expressions with a step limit |\n| [Std.Bytes](/module/Std.Bytes) | binary data, hex, and base64 |\n\n## Networking and the web\n\n| Module | For |\n| --- | --- |\n| [Std.Http.Server](/module/Std.Http.Server) | an HTTP server with routing, limits, and graceful shutdown |\n| [Std.Http.Client](/module/Std.Http.Client) | an HTTP client with verified TLS, redirects, and deadlines |\n| [Std.Html](/module/Std.Html) | HTML built as values, escaped by construction |\n| [Std.Url](/module/Std.Url) | parsing and building URLs |\n| [Std.Net](/module/Std.Net), [Std.Tls](/module/Std.Tls) | sockets and verified TLS connections |\n\n## Applications and databases\n\n| Module | For |\n| --- | --- |\n| [Std.App](/module/Std.App) | an application as a value: settings, stages, health checks |\n| [Std.App.Database](/module/Std.App.Database) | a database resource for SQLite or PostgreSQL |\n| [Std.Db.Migrate](/module/Std.Db.Migrate) | numbered schema migrations that run once |\n| [Std.Db.Store](/module/Std.Db.Store) | keeping a program's own values in a table |\n| [Std.Crypto](/module/Std.Crypto) | hashes, message authentication, and encryption |\n\n## Testing\n\n| Module | For |\n| --- | --- |\n| [Std.Test](/module/Std.Test) | test suites that `pudu test` discovers and runs |\n| [Std.Bench](/module/Std.Bench) | measuring how long code takes |\n\n## Reading the reference\n\nEvery declaration in the [API reference](/modules) shows its signature and its documentation. You can also search by type shape from the home page: searching `Str -> UInt32` finds functions that take text and return a 32-bit number.\n"},32  Chapter.Chapter{group: "docs", slug: "tooling", title: "Tooling", markdown: "# Tooling\n\nEverything is one command: `pudu`. It checks, runs, tests, formats, and documents programs, and it speaks the language server protocol for editors.\n\n## Commands\n\n| Command | Does |\n| --- | --- |\n| `pudu run <file>` | compiles a program and runs its `main` |\n| `pudu run --watch <file>` | runs it again whenever a source file changes |\n| `pudu run --watch --also <path> <file>` | also runs it again when anything under a path changes — pages, data, styles |\n| `pudu check <file>...` | compiles files and reports diagnostics without running them |\n| `pudu test [path]...` | discovers and runs test programs |\n| `pudu fmt <path>...` | rewrites files in the one supported format |\n| `pudu fmt --check <path>...` | reports unformatted files without changing them |\n| `pudu lint <path>...` | analyzes programs, with `--fix` for safe fixes |\n| `pudu doc <file>...` | describes every name a program declares, as text, `--json`, or `--html` |\n| `pudu search <query> <file>...` | finds a name, or a type shape such as `Array[a] -> a` |\n| `pudu build <file>` | writes one file that runs anywhere the compiler runs |\n| `pudu init [path]` | creates a project with a `pudu.toml` manifest |\n| `pudu install [what]...` | adds dependencies, or installs what `pudu.lock` names — see [Dependencies](/docs/dependencies) |\n| `pudu uninstall <name>...` | removes dependencies |\n| `pudu update [name]...`, `pudu upgrade [name]...` | moves to newer releases within, or past, the requirements |\n| `pudu login`, `pudu logout`, `pudu whoami` | stores, forgets, or names the GitHub token used to publish |\n| `pudu release <version>`, `pudu search [words]` | tags and publishes a release on GitHub, or lists packages |\n| `pudu update [name]...` | moves dependencies to the newest versions the manifest allows |\n| `pudu deps`, `pudu tree` | show the dependencies and the whole graph |\n| `pudu explain <file>` | runs a program and reports what running it cost |\n| `pudu repl [file]` | starts the interactive session |\n| `pudu lsp` | speaks the language server protocol over standard input and output |\n| `pudu version` | prints the version |\n\n## Formatting\n\nThere is one format, and `pudu fmt` writes it: two-space indentation, braces on the line that opens them, and trailing commas in multiline lists. The formatter only moves whitespace — the tokens it writes are the tokens it read — so formatting never changes what a program means. `pudu fmt --check` makes a good gate in continuous integration.\n\n## Tests\n\nA test program is an ordinary module whose `main` builds a suite with `Std.Test` and reports it:\n\n```pudu\nmodule MathTest\n\nimport Std.Test as Test\n\nfn double(n: Int) -> Int = n * 2\n\nexport fn main() -> Int \{\n  let suite = Test.suite(\"math\", &[\n      Test.that(\"doubling adds a number to itself\", double(21) == 42),\n      Test.not(\"doubling is not squaring\", double(3) == 9)\n    ])\n  Test.report(&Test.run(&suite))\n\}\n```\n\n`pudu test` discovers test programs under the paths it is given and runs each one.\n\n## Diagnostics\n\nEvery diagnostic has a code, such as `E3033` for calling a member a module does not export. The code names one kind of mistake, and the message says where it happened and how to fix it.\n\n## Watching a program\n\n`pudu run --watch` starts a program again each time a `.pudu` file under its project changes, and each `--also` path adds everything under it: a site's pages, data, and stylesheets. The program is told it is being watched: `PUDU_WATCH` counts its starts from 1, and `PUDU_WATCH_CHANGED` names the files that changed before this start, one per line. A service can pass that on — this site's pages reload themselves when the count moves, and take new styles in place when a stylesheet is all that changed — with nothing to configure.\n\n## Compiled modules are kept\n\nEach module the compiler parses and checks without a diagnostic is kept, so the next `pudu run`, `pudu check`, or `pudu test` reads it instead of compiling it again — the standard library included. An entry is keyed by the module's text and everything it read, so an edit anywhere a module depends on compiles it again; nothing stale is ever used. Only clean products are kept, so every diagnostic comes from the compile reporting it.\n\nThe products live in the user's cache directory, `$XDG_CACHE_HOME/pudu` or `~/.cache/pudu`, under a directory named for the compiler that wrote them, so a different compiler reads none of them. `PUDU_CACHE` names another directory, and `PUDU_CACHE=off` turns keeping off. The cache is bounded and drops the entries used least recently.\n\n## Editors\n\n`pudu lsp` is the compiler answering an editor, so the editor and `pudu check` never disagree about what a program means. It gives:\n\n- diagnostics as you type, with the same codes and help as the command line;\n- hover with the inferred type, and for a name another module exports, that module's documentation;\n- go to definition, into another module's file for an imported name, and to a module's file from its import;\n- completion of a value's fields and methods, a module's exports after `Io.`, whole module paths after `import`, a selection's names inside `import Std.List \{ … \}`, a match arm's variants after `case`, and a record literal's unset fields inside `Point\{ … \}`;\n- signature help, references, rename, highlights, inlay hints for inferred types, the outline, workspace symbols, and formatting.\n\nA document that is half written still gets answers: the server reads what it can of an unfinished line, and a request asked again at the same place is answered from what it already compiled. While it works it keeps reading, so a newer edit replaces an older one still waiting and a cancelled request stops its work.\n\nThe repository ships a VS Code extension in `editors/vscode` that runs the installed `pudu`. **Pudu: Restart Language Server** picks up a rebuilt compiler without reloading the window. The playground's editor asks the same server.\n"},33  Chapter.Chapter{group: "pages", slug: "conduct", title: "Contributor Covenant Code of Conduct", markdown: "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our community a\nharassment-free experience for everyone, regardless of age, body size, visible or invisible\ndisability, ethnicity, sex characteristics, gender identity and expression, level of experience,\neducation, socio-economic status, nationality, personal appearance, race, caste, color, religion, or\nsexual identity and orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and\nhealthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our community include:\n\n- Demonstrating empathy and kindness toward other people\n- Being respectful of differing opinions, viewpoints, and experiences\n- Giving and gracefully accepting constructive feedback\n- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the\n  experience\n- Focusing on what is best not just for us as individuals, but for the overall community\n\nExamples of unacceptable behavior include:\n\n- The use of sexualized language or imagery, and sexual attention or advances of any kind\n- Trolling, insulting or derogatory comments, and personal or political attacks\n- Public or private harassment\n- Publishing others' private information, such as a physical or email address, without their\n  explicit permission\n- Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of acceptable behavior\nand will take appropriate and fair corrective action in response to any behavior that they deem\ninappropriate, threatening, offensive, or harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject comments, commits,\ncode, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and\nwill communicate reasons for moderation decisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when an individual is\nofficially representing the community in public spaces. Examples of representing our community\ninclude using an official e-mail address, posting via an official social media account, or acting as\nan appointed representative at an online or offline event.\n\nFor Pudu this includes the repository — issues, pull requests, discussions, commit messages, and\ncode review — and any space where someone speaks for the project.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported to the\nmaintainer responsible for enforcement at <chrisperezsantiago1@gmail.com>. All complaints will be\nreviewed and investigated promptly and fairly.\n\nThe maintainer is obligated to respect the privacy and security of the reporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining the consequences for\nany action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or\nunwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing clarity around the\nnature of the violation and an explanation of why the behavior was inappropriate. A public apology\nmay be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series of actions.\n\n**Consequence**: A warning with consequences for continued behavior. No interaction with the people\ninvolved, including unsolicited interaction with those enforcing the Code of Conduct, for a\nspecified period of time. This includes avoiding interactions in community spaces as well as\nexternal channels like social media. Violating these terms may lead to a temporary or permanent ban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including sustained inappropriate\nbehavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public communication with the\ncommunity for a specified period of time. No public or private interaction with the people involved,\nincluding unsolicited interaction with those enforcing the Code of Conduct, is allowed during this\nperiod. Violating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community standards, including\nsustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement\nof classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within the community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at\nhttps://www.contributor-covenant.org/version/2/1/code_of_conduct.html.\n\nCommunity Impact Guidelines were inspired by\n[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see the FAQ at\nhttps://www.contributor-covenant.org/faq. Translations are available at\nhttps://www.contributor-covenant.org/translations.\n"},34  Chapter.Chapter{group: "pages", slug: "contributing", title: "Contributing to Pudu", markdown: "# Contributing to Pudu\n\nPudu is developed as a language specification and compiler together. The FMCF vault is normative: read `wiki/00-INDEX.md`, `wiki/architecture/SEMANTICS.md`, and `wiki/architecture/DELIVERY.md` before proposing language or compiler changes.\n\nThe local files `fmcf.md`, `lang_proposal.md`, and `goal.md` are private inputs. Never stage, commit, quote, attach, or reproduce them in issues, PRs, diagnostics, artifacts, or release notes. Public work cites the distilled vault pages and ADRs.\n\n## Running the gates locally\n\n```bash\nbash test/gates.sh\n```\n\nRuns what CI runs, in CI's order, and names the gate that failed.\n\nThe script removes the build products first, and that is not incidental. A\nfresh checkout cannot be up to date, so CI's gates always compile; locally\n`cabal` frequently answers \"Up to date\" after a source has changed, and a gate\nthat did not compile reports a clean tree while checking none of it. That has\nhidden real errors in this repository more than once.\n\n`--ghc-options=-fforce-recomp` does **not** fix it. That flag is GHC's, and when\n`cabal` decides the package is up to date it never invokes GHC, so the flag is\nnever seen. Removing the build products is the only thing that makes the next\nbuild real. It costs minutes and buys an answer worth having.\n\n## Starting work\n\n1. Select or create one ready GitHub issue with a bounded vertical slice.\n2. Confirm the governing wiki module/semantic pages and ADR are complete.\n3. Fetch and fast-forward `dev`.\n4. Create `feature/<issue>-<slug>` (or `fix/`, `perf/`, `docs/` as appropriate) from `dev`.\n5. Keep the branch focused on that issue.\n\nAn issue is ready only when its behavior, risks, acceptance criteria, test obligations, and wiki links are resolved. Architecture questions are settled in the vault before implementation.\n\n## Changes and commits\n\n- Keep implementation files under 500 lines by default.\n- Target fewer than 400 changed lines per PR and split before 600 unless excess is isolated generated or snapshot data.\n- Use semantic commits such as `feat(parser): parse guarded match arms refs #42`.\n- Keep code, tests, and matching wiki changes synchronized.\n- Do not add generated authorship or assistant attribution.\n\n## Verification\n\nEvery feature proves:\n\n- valid behavior;\n- invalid behavior;\n- the regression risk that could return;\n- diagnostic code/span or user-facing output when applicable;\n- formatter/linter stability;\n- full-suite compatibility when practical.\n\nCompiler changes also cover the affected lexer/parser/AST/type/ownership/exhaustiveness/backend/CLI layers. Native features compare interpreter and compiled behavior where applicable.\n\n## Review\n\nOpen a PR to `dev` with `Closes #<issue>`; mandatory intermediate size partitions use `Refs #<issue>`, keep it open, and name the exact remaining action. Explain behavior, reviewability, validation, and deferred boundaries concisely.\n\nThe author performs a self-audit, then an independent reviewer checks correctness, semantic conformance, diagnostics, performance risks, and test strength. Semantic, ABI, or public API changes require Language Architect approval. A Forensic Guardian confirms wiki/source parity and history updates.\n\nReview findings use P0 through P3 severity as defined in `wiki/architecture/DELIVERY.md`. P0/P1 findings block merge. With only one GitHub identity, independent agent review must be preserved in a PR comment or CI artifact; native approval enforcement requires another maintainer account.\n\n## Merge and release\n\nFeature PRs use merge commits so reviewed intermediate commits remain bisectable, then delete the feature branch. `dev` must remain buildable.\n\nReleases branch as `release/X.Y.Z` from `dev`, promote by PR to `main`, receive annotated tag `vX.Y.Z`, and synchronize any release-only metadata back to `dev`. The `release` workflow does the tagging and publishing: a push to `main` that changes `packages/pudu/` at a version with no tag builds and checks the Linux and macOS archives, tags the commit, and publishes the release, marked pre-release for a `0.x` version. A merge that changes only the README, the website, the examples, or the wiki does not start it, any other push releases nothing unless the plan finds a change under `packages/pudu/`, and a `release/` branch builds the archives without publishing. Each version needs its notes in `packages/pudu/v0.1/release-notes/X.Y.Z.md`. Semantic releases update the semantic revision ledger and cite their ADRs.\n"},35  Chapter.Chapter{group: "pages", slug: "security", title: "Security policy", markdown: "# Security policy\n\n## Reporting a vulnerability\n\nReport a suspected vulnerability privately through GitHub's\n[security advisory form](https://github.com/chrismichaelps/pudu-lang/security/advisories/new), or by\nemail to <chrisperezsantiago1@gmail.com> with `SECURITY` in the subject.\n\nPlease do not open a public issue for a vulnerability. A public report tells everyone how to use the\nproblem before there is a version that fixes it.\n\nInclude what you need to make the problem happen again: the version `pudu version` prints, the\nplatform, and the smallest program that shows it. A proof of concept is welcome and is never\nrequired.\n\nYou can expect an acknowledgement within seven days and a decision on whether the report is accepted\nwithin thirty. Pudu is maintained by one person, so an acknowledgement may be all that arrives while\nthe report is still being investigated.\n\n## What is in scope\n\nPudu runs programs and ships a standard library that speaks to the network, the filesystem, and\ndatabases. A report is in scope when it lets a program do something its source does not say it does,\nor lets input decide something the program never gave it. That includes:\n\n- The compiler or evaluator running code a program's source does not contain.\n- A standard library reader that a crafted input drives out of its bounds, into unbounded memory, or\n  into a hang.\n- `Std.Tls` accepting a certificate it should reject, or failing to verify a chain or hostname.\n- `Std.Db` placing a parameter into statement text rather than binding it, or a pool handing one\n  borrower's transaction to another.\n- `Std.Http.Server` mixing one connection's request or response with another's.\n- A cryptographic routine that does not compute what it is named for.\n- The published archives or the release workflow shipping something other than what the tagged\n  source builds.\n\n## What is not in scope\n\n- A program that is given a capability and uses it. A signature says what a function may do, and a\n  program that opens a socket or reads a file is doing what it was written to do.\n- Resources that rely on an explicit `close`. Several opaque resources still need one, cancellation\n  does not yet propagate between workers, and this is recorded as open work in\n  [`wiki/architecture/RELEASE-READINESS.md`](wiki/architecture/RELEASE-READINESS.md) rather than\n  treated as a vulnerability.\n- Denial of service by simply providing more input than a machine has memory for, on a reader whose\n  bounds have not been measured yet. The readers whose memory is proven flat are named in the\n  readiness document; the others are open work.\n- Findings in third-party libraries reached through the foreign boundary. Report those upstream; if\n  the binding is what makes the problem reachable, that part is in scope.\n\n## Supported versions\n\n| Version | Supported |\n| ------- | --------- |\n| 0.1.x   | Yes       |\n\nPudu is pre-release. Fixes land on the next version rather than being backported, and there is no\nlong-term support branch yet. When a release fixes a vulnerability its notes say so, and the advisory\nis published on the repository's security page.\n"},36  Chapter.Chapter{group: "pages", slug: "community", title: "Community", markdown: "# Community\n\nPudu is early. It is maintained by one person, which means the fastest way to influence the language\nright now is to use it and say what happened.\n\n## Where things happen\n\nEverything is on GitHub.\n\n- **[Issues](https://github.com/chrismichaelps/pudu-lang/issues)** — bugs, and anything the compiler\n  told you that you could not act on. A confusing diagnostic is a bug worth reporting.\n- **[Discussions](https://github.com/chrismichaelps/pudu-lang/discussions)** — everything that is not\n  a bug. [Q&A](https://github.com/chrismichaelps/pudu-lang/discussions/categories/q-a) for how to\n  write something, [Ideas](https://github.com/chrismichaelps/pudu-lang/discussions/categories/ideas)\n  for proposals before they become issues.\n- **[Pull requests](https://github.com/chrismichaelps/pudu-lang/pulls)** — see\n  [Contributing](/contributing) first for what a change has to pass.\n\nThere is no chat server, forum, or mailing list yet. When there are enough people for one to be worth\nreading, this page will say where it is.\n\n## Reporting something that went wrong\n\nThe report that gets fixed fastest has three things in it: the program, the command you ran, and what\n`pudu` printed. Every diagnostic carries a code such as `E3078`, and quoting it identifies the exact\ncheck that fired.\n\nIf the program is large, the useful version is the smallest one that still misbehaves. Reducing it is\noften how the cause becomes obvious.\n\nFor anything with security consequences, do not open a public issue. [Security](/security) explains\nhow to report privately and what is in scope.\n\n## Asking a question\n\nQuestions are welcome in\n[Q&A](https://github.com/chrismichaelps/pudu-lang/discussions/categories/q-a), including ones you\nthink are obvious. If the documentation led you astray, that is a documentation bug, and saying which\npage and what you expected is more useful than the answer itself.\n\nBefore asking, the [documentation](/docs) is twenty chapters and every example in it runs as written,\nand the [standard library reference](/modules) is searchable by name and by type signature.\n\n## What is most useful right now\n\nPudu is pre-release, so the most valuable feedback is about friction rather than polish:\n\n- Programs you tried to write and could not, or could only write awkwardly.\n- Standard library functions you expected to exist and did not find.\n- Diagnostics that told you something was wrong without telling you what to do.\n- Anything in the documentation that turned out to be untrue.\n\nEveryone taking part is expected to follow the [Code of Conduct](/conduct).\n"},37  Chapter.Chapter{group: "pages", slug: "privacy", title: "Privacy", markdown: "# Privacy\n\nThis site does not track you.\n\n## What it does not do\n\n- **No analytics.** There is no Google Analytics, no Plausible, no Fathom, no Segment, and no\n  telemetry of any kind.\n- **No cookies.** The site sets none, so there is no consent banner to dismiss.\n- **No third-party scripts.** The pages carry no executable JavaScript at all. The only `<script>`\n  tag on a page holds structured data for search engines, which is data rather than code.\n- **No accounts.** There is nothing to sign in to and no form that asks who you are.\n- **No fonts or assets from anyone else.** The typeface is served from this site, so loading a page\n  does not tell another company that you read it.\n\nYou can check all of this. Open the page source, or read\n[the code that renders it](https://github.com/chrismichaelps/pudu-lang/tree/dev/website) — this site\nis a Pudu program, and every page it can serve is in that directory.\n\n## What is unavoidable\n\nThe site is hosted on Vercel, and a request has to reach a server to be answered. Vercel keeps\noperational logs for that, which include your IP address, and its own privacy policy governs them.\nNothing in those logs is read, analysed, or exported by this project.\n\nThe documentation search runs on the server, so a search query reaches it in the URL. Queries are not\nstored by this project and are not associated with anything.\n\n## Downloads\n\nArchives are hosted on GitHub Releases. Downloading one is a request to GitHub, and GitHub's privacy\npolicy applies to it. The compiler itself sends nothing anywhere: `pudu` makes no network request\nunless the program you run makes one.\n\n## Changes\n\nIf this ever stops being true, this page changes first and the change is visible in the repository's\nhistory.\n\nQuestions about this page can go to <chrisperezsantiago1@gmail.com>.\n"},38  Chapter.Chapter{group: "pages", slug: "brand", title: "Brand and logo", markdown: "# Brand and logo\n\nThe Pudu name and logo identify this project. These rules exist so that a reader can tell what is\nPudu and what is someone else's work built with it.\n\n## The name\n\n**Pudu** is capitalised as a proper noun. The command is `pudu`, lower case, set in code when it\nappears in prose. Source files end in `.pudu`.\n\nA pudú is a small deer from South America. The language is named after it, and the name is not an\nacronym, so it is never written PUDU.\n\n## Using the logo\n\nThe logo may be used without asking to:\n\n- link to this site or to the repository,\n- illustrate an article, talk, or tutorial about Pudu,\n- say that your project is written in Pudu, or that your library or tool works with it.\n\nWhen using it, keep clear space around the logo of at least the height of the letter `P`, and do not\nplace it on a background that leaves it hard to read. Do not stretch it, recolour it, rotate it, add\neffects to it, or rebuild it from parts.\n\n## What needs asking first\n\nDo not use the logo or the name in a way that suggests this project made, endorses, or maintains\nsomething it does not. In particular, do not use them:\n\n- as your own product, company, or application icon,\n- in your project's name in a way that reads as official, such as \"Pudu Cloud\" or \"Pudu Enterprise\",\n- on merchandise for sale,\n- in a domain name that reads as an official Pudu site.\n\nA name of the form \"X for Pudu\" or \"Pudu bindings for X\" is fine and needs no permission. If you are\nunsure, ask at <chrisperezsantiago1@gmail.com>.\n\n## Files\n\nThe logo is in the repository under\n[`website/public/assets`](https://github.com/chrismichaelps/pudu-lang/tree/dev/website/public/assets):\nthe full logo with the wordmark, and the short mark on its own. Use the full logo where there is room\nand the short mark where there is not.\n\n## Licence\n\nThe compiler, the standard library, and the documentation are licensed under\n[Apache-2.0](https://github.com/chrismichaelps/pudu-lang/blob/dev/LICENSE). That licence covers the\ncode, not the name or the logo, which these rules cover instead.\n"},39  Chapter.Chapter{group: "releases", slug: "0.1.0", title: "Pudu 0.1.0", markdown: "This is the first release of Pudu, and it is a pre-release. The language works, the standard library\nis broad, and the tooling is real, but the shape of both can still change before 1.0. Use it to write\nprograms, and tell me where it gets in the way.\n\n## Install\n\nDownload the archive for your machine, check it, and put its `bin` directory on your `PATH`:\n\n```sh\nshasum -a 256 -c pudu-0.1.0-darwin-arm64.tar.gz.sha256\ntar -xzf pudu-0.1.0-darwin-arm64.tar.gz\nexport PATH=\"$PWD/pudu-0.1.0-darwin-arm64/bin:$PATH\"\npudu version\n```\n\nThe standard library sits beside the executable inside the archive, so nothing is installed anywhere\nelse and deleting the directory removes Pudu. There are archives for Linux x86-64 and for macOS on\nApple silicon. Windows is not supported yet; to build for anything else, see the README.\n\n## The language\n\nPudu is statically typed and expression-oriented. A function that can fail returns `Result`, a value\nthat may be absent is an `Option`, and `match` has to cover every case. A signature tells you whether\na function changes what you hand it.\n\nThis release has records and sum types, generics with trait bounds, traits and `dynamic` trait\nvalues, `if let`, `let … else`, `while let`, labelled loops, and `?` for both `Result` and `Option`.\nNumbers include exact decimals and fixed-width integers that are checked rather than wrapped. Modules\ncan hold constants. Async functions run inside structured scopes. You can assign through `&mut`, to a\n`mut` field, and to an array element, and the checker refuses the writes that would not hold.\n\n## The standard library\n\n173 modules, 3,456 public declarations, every one of them documented. Collections and text. Files and\nprocesses. JSON, CSV, TOML, YAML and XML. HTTP clients and servers, with TLS that verifies. SQLite and\nPostgreSQL, including the PostgreSQL wire protocol written in Pudu. Cryptography, workers and\nchannels, and a testing module with property checks. The native interface, audio and video layer is\nwritten in Pudu too.\n\n## The tooling\n\nOne command. `pudu` runs, checks, tests, formats, lints, documents, searches and bundles programs,\nstarts a project with `pudu init`, and talks to editors over the Language Server Protocol.\n\nThe documentation is twenty chapters, from a first program through to HTTP services. Every example in\nit is a complete program that compiles and runs as written, and all 87 of them were run against this\nbuild.\n\n## What is not here yet\n\nThere is no package manager. Dependencies are local directories, and `lock`, `fetch`, `update` and\n`publish` are specified but not implemented. If you were waiting to depend on someone else's Pudu\ncode, keep waiting.\n\nPrograms run on an interpreter, so this is not the release to benchmark against a compiled language.\n\nSome resources still need an explicit `close` rather than being released when they go out of scope:\nsockets, processes, workers and database connections rely on that or on teardown when the program\nends. Cancellation does not yet propagate between workers. This is the main thing standing between\nPudu and a stable release.\n\nMemory use is proven flat for reading files, CSV and JSON Lines as input grows. The network, HTTP and\ndatabase readers have not been measured that way, so do not assume they hold a gigabyte-sized stream\nthe same way.\n\n## Reporting problems\n\nOpen an issue with the program, the command you ran, and what `pudu` printed. Every diagnostic has a\ncode such as `E3078`, and quoting it is the fastest way to say what happened.\n"},40  Chapter.Chapter{group: "releases", slug: "0.1.1", title: "Pudu 0.1.1", markdown: "This is the second pre-release of Pudu. Its headline is packages: Pudu code can now depend on other\nPudu code published on GitHub, and `pudu init` makes projects that are ready to install\ndependencies and to be published. The language and its tooling can still change before 1.0.\n\n## Install\n\nDownload the archive for your machine, check it, and put its `bin` directory on your `PATH`:\n\n```sh\nshasum -a 256 -c pudu-0.1.1-darwin-arm64.tar.gz.sha256\ntar -xzf pudu-0.1.1-darwin-arm64.tar.gz\nexport PATH=\"$PWD/pudu-0.1.1-darwin-arm64/bin:$PATH\"\npudu version\n```\n\nThe standard library sits beside the executable inside the archive, so nothing is installed anywhere\nelse and deleting the directory removes Pudu. There are archives for Linux x86-64 and for macOS on\nApple silicon. Windows is not supported yet.\n\n## Packages\n\nA package is a GitHub repository named `@owner/repo`, marked with the `pudu-package` topic, and a\nrelease is a tag. There is no separate registry service.\n\n- `pudu install` adds a dependency from GitHub (`@alice/json`, `@alice/json@1.4.2`), a Git URL, or a\n  local path, and installs what `pudu.toml` and `pudu.lock` name into `deps/`. `--locked` refuses\n  to change the lock, and a failed install changes neither the lock nor `deps/`.\n- `pudu uninstall`, `update`, `upgrade`, `deps`, and `tree` manage and show the dependency graph.\n- `pudu login`, `whoami`, and `pudu release <version>` publish: the release checks the manifest,\n  the sources, the tests, and a clean tree, then pushes the tag and creates the GitHub release.\n- `pudu search <words>` finds published packages. `pudu search <query> <file>...` is still the\n  declaration search over your own sources.\n\n## Projects\n\n- `pudu init` writes a manifest with the package fields a publication needs: name, version,\n  description, license, keywords, language, and source.\n- `pudu init --lib --name @owner/repo` starts a library under its package's module root, with a\n  test that imports it.\n- A suite under `test/` imports the project's modules from `src/` without declaring anything.\n  Manifests from 0.1.0 that name `src = \"src\"` as a dependency keep working, and no root is ever\n  searched twice.\n\n## The language and tooling\n\n- Short function literals, first-class ranges with slicing, and destructuring bindings.\n- The language server completes and explains code while it is half written, follows imports in open\n  editors, and drops superseded work.\n- `pudu run --watch --also <path>` restarts for data and assets as well as sources, and\n  `pudu run --confined` runs a program without files, processes, the network, or foreign code.\n- Compiled modules are reused across runs, and a program's constants are bound once at link time.\n\n## Fixes\n\nChecker fixes for chained calls, block scoping, and aliases reached through modules; method dispatch\nthat considers only implementations; HTTP handlers that fail answer 500 and keep their worker; tar\npaths longer than 100 bytes; and process reads that split a character.\n\n## What is not here yet\n\nPrograms still run on an interpreter. Some resources still need an explicit `close`, and\ncancellation does not yet propagate between workers. Both stand between Pudu and a stable release.\n\n## Reporting problems\n\nOpen an issue with the program, the command you ran, and what `pudu` printed. Every diagnostic has a\ncode such as `E3078`, and quoting it is the fastest way to say what happened.\n"},41  Chapter.Chapter{group: "examples", slug: "hello", title: "Hello, Pudu", markdown: "# Hello, Pudu\n\n```pudu\n// Hello, Pudu\n// A complete program: a module, an import, and a main function whose result is the exit status.\nmodule Main\n\nimport Std.Io as Io\n\nconst GREETING: Str = \"Hello\"\n\nfn greet(name: Str) -> Str \{\n  \"\{GREETING\}, \{name\}!\"\n\}\n\nfn main() -> Int \{\n  for name in [\"Pudu\", \"playground\"] \{\n    let _said = Io.writeLine(greet(name))\n  \}\n  0\n\}\n```\n"},42  Chapter.Chapter{group: "examples", slug: "functions", title: "Functions", markdown: "# Functions\n\n```pudu\n// Functions\n// Expression bodies, default values, recursion, closures, and the short |x| form.\nmodule Main\n\nimport Std.Io as Io\n\nfn square(n: Int) -> Int = n * n\n\nfn greet(name: Str, greeting: Str = \"Hello\") -> Str \{\n  \"\{greeting\}, \{name\}!\"\n\}\n\nfn fibonacci(n: Int) -> Int \{\n  if n < 2 \{ return n \}\n  fibonacci(n - 1) + fibonacci(n - 2)\n\}\n\nfn applyTwice(value: Int, step: fn(Int) -> Int) -> Int \{\n  step(step(value))\n\}\n\nfn adder(amount: Int) -> fn(Int) -> Int \{\n  fn(n: Int) => n + amount\n\}\n\nfn main() -> Int \{\n  let _plain = Io.writeLine(greet(\"Pudu\"))\n  let _warm = Io.writeLine(greet(\"Pudu\", \"Welcome\"))\n  let _squared = Io.writeLine(\"square(7) = \{square(7)\}\")\n  let _fib = Io.writeLine(\"fibonacci(20) = \{fibonacci(20)\}\")\n\n  let addTen = adder(10)\n  let _twice = Io.writeLine(\"applyTwice(1, addTen) = \{applyTwice(1, addTen)\}\")\n  let _named = Io.writeLine(\"applyTwice(3, square) = \{applyTwice(3, square)\}\")\n\n  let numbers = [1, 2, 3, 4, 5, 6]\n  let evens = numbers.filter(|n| n % 2 == 0)\n  let total = numbers.reduce(|carried, n| carried + n, 0)\n  let _short = Io.writeLine(\"evens \{evens\}, total \{total\}\")\n  0\n\}\n```\n"},43  Chapter.Chapter{group: "examples", slug: "shapes", title: "Shapes", markdown: "# Shapes\n\n```pudu\n// Shapes\n// Records and sum types, taken apart with match.\nmodule Main\n\nimport Std.Io as Io\n\ntype Point = \{ x: Float64, y: Float64 \}\n\ntype Shape =\n  | Circle(Point, Float64)\n  | Rectangle(Point, Point)\n  | Triangle(Point, Point, Point)\n\nfn area(shape: &Shape) -> Float64 \{\n  match shape \{\n    case Circle(_, radius) => 3.14159 * radius * radius\n    case Rectangle(low, high) => (high.x - low.x) * (high.y - low.y)\n    case Triangle(a, b, c) => \{\n      let doubled = a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y)\n      if doubled < 0.0 \{ -doubled / 2.0 \} else \{ doubled / 2.0 \}\n    \}\n  \}\n\}\n\nfn name(shape: &Shape) -> Str \{\n  match shape \{\n    case Circle(_, _) => \"circle\"\n    case Rectangle(_, _) => \"rectangle\"\n    case Triangle(_, _, _) => \"triangle\"\n  \}\n\}\n\nfn main() -> Int \{\n  let origin = Point\{x: 0.0, y: 0.0\}\n  let shapes = [\n    Circle(origin, 1.0),\n    Rectangle(origin, Point\{x: 2.0, y: 3.0\}),\n    Triangle(origin, Point\{x: 4.0, y: 0.0\}, Point\{x: 0.0, y: 3.0\})\n  ]\n  var total = 0.0\n  for shape in shapes \{\n    let size = area(&shape)\n    total = total + size\n    let _said = Io.writeLine(\"\{name(&shape)\}: \{size\}\")\n  \}\n  let _sum = Io.writeLine(\"total: \{total\}\")\n  0\n\}\n```\n"},44  Chapter.Chapter{group: "examples", slug: "numbers", title: "Numbers", markdown: "# Numbers\n\n```pudu\n// Numbers\n// Fixed widths, wrapping and saturating arithmetic, exact decimals, and whole numbers of any size.\nmodule Main\n\nimport Std.Decimal as D\nimport Std.Io as Io\nimport Std.Num \{Integer\}\n\nfn factorial(n: BigInt) -> BigInt \{\n  var product: BigInt = 1\n  var step: BigInt = 2\n  while step <= n \{\n    product = product * step\n    step = step + 1\n  \}\n  product\n\}\n\nfn main() -> Int \{\n  // A UInt8 holds 0 through 255. Plain + would stop the program here;\n  // &+ wraps around and +| stops at the limit, because the program asked.\n  let level: UInt8 = 250u8\n  let _wrap = Io.writeLine(\"250 &+ 10 = \{level &+ 10u8\}\")\n  let _clip = Io.writeLine(\"250 +| 10 = \{level +| 10u8\}\")\n\n  // Narrowing answers an Option: 300 does not fit in a byte.\n  let wide = 300.toBigInt()\n  let _byte = Io.writeLine(\"300 as UInt8: \{0u8.fromBigInt(wide)\}\")\n  let _short = Io.writeLine(\"300 as Int16: \{0i16.fromBigInt(wide)\}\")\n\n  // Decimals keep the digits that were written.\n  let _float = Io.writeLine(\"0.1 + 0.2 as Float64: \{0.1 + 0.2\}\")\n  let _exact = Io.writeLine(\"0.1 + 0.2 as Decimal: \{D.toText(0.1d + 0.2d)\}\")\n  let subtotal = D.sum([19.99d, 5.01d, 0.10d])\n  let tax = D.round(subtotal * 0.0825d, 2, D.HalfEven)\n  let _bill = Io.writeLine(\"subtotal \{D.toText(subtotal)\}, tax \{D.toText(tax)\}, total \{D.toText(subtotal + tax)\}\")\n\n  // BigInt grows as it needs to.\n  let _big = Io.writeLine(\"40! = \{factorial(40)\}\")\n\n  // Try replacing &+ with + above to see checked arithmetic stop the program.\n  0\n\}\n```\n"},45  Chapter.Chapter{group: "examples", slug: "text", title: "Text", markdown: "# Text\n\n```pudu\n// Text\n// Interpolation, splitting and joining, characters, padding, and reading numbers out of text.\nmodule Main\n\nimport Std.Io as Io\nimport Std.Text as Text\n\nconst SCORES: Str = \"ada: 36\\ngrace: 45\\nalan: 41\\nbad line\\nlinus: many\"\n\nfn row(name: Str, score: Int) -> Str \{\n  Text.padRight(Text.capitalize(name), 8, \".\") + Text.padLeft(\"\{score\}\", 4, \" \")\n\}\n\nfn main() -> Int \{\n  let name = \"Pudu\"\n  let _hello = Io.writeLine(\"\{name\} has \{name.length()\} letters, upper-cased \{name.toUpper()\}\")\n  let _braces = Io.writeLine(\"braces are written \\\{like this\\\}\")\n\n  let words = \"the smallest deer in the world\".split(\" \")\n  let _words = Io.writeLine(\"\{words.length()\} words, joined: \{words.join(\"-\")\}\")\n  let _replace = Io.writeLine(\"the world\".replace(\"world\", \"forest\"))\n\n  var vowels = 0\n  for character in \"pudu lives in chile\".chars() \{\n    if \"aeiou\".contains(character.toText()) \{ vowels = vowels + 1 \}\n  \}\n  let _vowels = Io.writeLine(\"\{vowels\} vowels\")\n\n  // Text.wholeOf answers None when the text is not a whole number.\n  for line in SCORES.lines() \{\n    let parts = line.split(\":\")\n    if parts.length() != 2 \{\n      let _skipped = Io.writeLine(\"skipped: '\{line\}'\")\n      continue\n    \}\n    match Text.wholeOf(parts[1].trim()) \{\n      case Some(score) => \{ let _row = Io.writeLine(row(parts[0], score)) \}\n      case None => \{ let _bad = Io.writeLine(\"not a number: '\{parts[1].trim()\}'\") \}\n    \}\n  \}\n  0\n\}\n```\n"},46  Chapter.Chapter{group: "examples", slug: "words", title: "Counting words", markdown: "# Counting words\n\n```pudu\n// Counting words\n// Arrays, maps, and sorting: the most frequent words in a passage.\nmodule Main\n\nimport Std.Io as Io\nimport Std.List as List\nimport Std.Map as Map\n\nconst PASSAGE: Str = \"the pudu is the smallest deer in the world and the pudu lives in the forests of chile and argentina where the forest is dense\"\n\nfn counted(words: &Array[Str]) -> Map[Str, Int] \{\n  var counts: Map[Str, Int] = mapOf([])\n  for word in *words \{\n    let seen = match counts.get(word) \{\n      case Some(count) => count\n      case None => 0\n    \}\n    counts = counts.insert(word, seen + 1)\n  \}\n  counts\n\}\n\nfn main() -> Int \{\n  let words = PASSAGE.split(\" \")\n  let counts = counted(&words)\n  let ranked = List.sortBy(&Map.toArray(&counts), fn(left: (Str, Int), right: (Str, Int)) -> Bool \{\n      if left[1] != right[1] \{ left[1] > right[1] \} else \{ left[0] < right[0] \}\n    \})\n  let _total = Io.writeLine(\"\{words.length()\} words, \{ranked.length()\} different\")\n  var shown = 0\n  for entry in ranked \{\n    if shown < 5 \{\n      let _said = Io.writeLine(\"\{entry[1]\}  \{entry[0]\}\")\n      shown = shown + 1\n    \}\n  \}\n  0\n\}\n```\n"},47  Chapter.Chapter{group: "examples", slug: "collections", title: "Ranges, slices, and sets", markdown: "# Ranges, slices, and sets\n\n```pudu\n// Ranges, slices, and sets\n// Arrays that never change in place, ranges, slices, set literals, and map, filter, and reduce.\nmodule Main\n\nimport Std.Io as Io\nimport Std.List as List\n\nfn main() -> Int \{\n  // A range counts; 1..=10 includes its end.\n  var squares: Array[Int] = []\n  for n in 1..=10 \{\n    squares = squares.push(n * n)\n  \}\n  let _squares = Io.writeLine(\"squares \{squares\}\")\n\n  // A slice takes part of an array.\n  let _first = Io.writeLine(\"first three \{squares[0..3]\}\")\n  let _last = Io.writeLine(\"from the eighth \{squares[7..]\}\")\n\n  // Operations answer new arrays; the original is untouched.\n  let evens = squares.filter(|n| n % 2 == 0)\n  let halves = evens.map(|n| n / 2)\n  let total = squares.reduce(|sum, n| sum + n, 0)\n  let _evens = Io.writeLine(\"even squares \{evens\}, halved \{halves\}, all added \{total\}\")\n  let _sorted = Io.writeLine(\"largest first \{List.sortBy(&squares, |a, b| a > b)[0..3]\}\")\n\n  // A set holds each member once, kept in sorted order.\n  let visited = #\{\"chile\", \"argentina\", \"chile\", \"peru\"\}\n  let planned = #\{\"peru\", \"bolivia\"\}\n  let _visited = Io.writeLine(\"visited \{visited.size()\} countries: \{visited\}\")\n  let _peru = Io.writeLine(\"peru visited? \{\"peru\" in visited\}; bolivia? \{\"bolivia\" in visited\}\")\n  let _both = Io.writeLine(\"in both: \{visited.intersect(planned)\}, in either: \{visited.union(planned)\}\")\n  0\n\}\n```\n"},48  Chapter.Chapter{group: "examples", slug: "control-flow", title: "Control flow", markdown: "# Control flow\n\n```pudu\n// Control flow\n// if as a value, match with or-patterns, if let, let else, while, loop with a value, and labels.\nmodule Main\n\nimport Std.Io as Io\nimport Std.Text as Text\n\ntype Command =\n  | Move(Int)\n  | Turn(Str)\n  | Wait\n  | Stop\n\nfn describe(command: &Command) -> Str \{\n  match command \{\n    case Move(steps) => if steps == 1 \{ \"move one step\" \} else \{ \"move \{steps\} steps\" \}\n    case Turn(\"left\") | Turn(\"right\") => \"turn\"\n    case Turn(other) => \"cannot turn \{other\}\"\n    case Wait | Stop => \"stand still\"\n  \}\n\}\n\nfn portOf(text: Str) -> Int \{\n  let Some(port) = Text.wholeOf(text) else \{ return 80 \}\n  port\n\}\n\nfn main() -> Int \{\n  for command in [Move(3), Move(1), Turn(\"left\"), Turn(\"up\"), Wait] \{\n    let _said = Io.writeLine(describe(&command))\n  \}\n\n  if let Some(value) = Text.wholeOf(\"42\") \{\n    let _found = Io.writeLine(\"if let found \{value\}\")\n  \}\n  let _ports = Io.writeLine(\"ports \{portOf(\"8080\")\} and \{portOf(\"http\")\}\")\n\n  var countdown = 3\n  while countdown > 0 \{\n    let _tick = Io.writeLine(\"countdown \{countdown\}\")\n    countdown = countdown - 1\n  \}\n\n  var guess = 1\n  let power = loop \{\n    guess = guess * 2\n    if guess > 100 \{ break guess \}\n  \}\n  let _power = Io.writeLine(\"first power of two above 100: \{power\}\")\n\n  var pair = (0, 0)\n  @rows for row in 1..=5 \{\n    for column in 1..=5 \{\n      if row * column == 12 \{\n        pair = (row, column)\n        break @rows\n      \}\n    \}\n  \}\n  let _pair = Io.writeLine(\"first pair whose product is 12: \{pair\}\")\n  0\n\}\n```\n"},49  Chapter.Chapter{group: "examples", slug: "errors", title: "Errors as values", markdown: "# Errors as values\n\n```pudu\n// Errors as values\n// Work that can fail answers a Result, and ? passes a failure up to the caller.\nmodule Main\n\nimport Std.Io as Io\nimport Std.Text as Text\n\ntype ParseError =\n  | Empty\n  | NotANumber(Str)\n  | OutOfRange(Int)\n\nfn explain(problem: &ParseError) -> Str \{\n  match problem \{\n    case Empty => \"nothing was written\"\n    case NotANumber(text) => \"'\{text\}' is not a number\"\n    case OutOfRange(value) => \"\{value\} is not a percentage\"\n  \}\n\}\n\nfn percentage(text: Str) -> Result[Int, ParseError] \{\n  let trimmed = text.trim()\n  if trimmed.isEmpty() \{ return Err(Empty) \}\n  let value = match Text.wholeOf(trimmed) \{\n    case Some(number) => number\n    case None => \{ return Err(NotANumber(trimmed)) \}\n  \}\n  if value < 0 || value > 100 \{ Err(OutOfRange(value)) \} else \{ Ok(value) \}\n\}\n\nfn average(texts: &Array[Str]) -> Result[Int, ParseError] \{\n  var total = 0\n  for text in *texts \{\n    total = total + percentage(text) ?\n  \}\n  Ok(total / texts.length())\n\}\n\nfn report(texts: &Array[Str]) -> () \{\n  match average(texts) \{\n    case Ok(value) => \{ let _said = Io.writeLine(\"average: \{value\}%\") \}\n    case Err(problem) => \{ let _said = Io.writeLine(\"refused: \" + explain(&problem)) \}\n  \}\n\}\n\nfn main() -> Int \{\n  report(&[\"40\", \"60\", \"95\"])\n  report(&[\"40\", \"sixty\"])\n  report(&[\"40\", \"140\"])\n  report(&[\"\", \"10\"])\n  0\n\}\n```\n"},50  Chapter.Chapter{group: "examples", slug: "ownership", title: "Borrowing and changing", markdown: "# Borrowing and changing\n\n```pudu\n// Borrowing and changing\n// A signature says whether a function reads a value or changes it: & borrows, &mut lends it to be changed.\nmodule Main\n\nimport Std.Io as Io\n\ntype Account = \{ owner: Str, mut balance: Int \}\n\nfn describe(account: &Account) -> Str \{\n  \"\{account.owner\} has \{account.balance\}\"\n\}\n\nfn deposit(account: &mut Account, amount: Int) -> () \{\n  account.balance = account.balance + amount\n\}\n\nfn withdraw(account: &mut Account, amount: Int) -> Result[(), Str] \{\n  if amount > account.balance \{\n    return Err(\"\{account.owner\} cannot withdraw \{amount\}\")\n  \}\n  account.balance = account.balance - amount\n  Ok(())\n\}\n\nfn main() -> Int \{\n  var account = Account\{owner: \"Ada\", balance: 10\}\n  deposit(&mut account, 25)\n  let _after = Io.writeLine(describe(&account))\n  match withdraw(&mut account, 100) \{\n    case Ok(_) => \{ let _said = Io.writeLine(\"withdrew 100\") \}\n    case Err(reason) => \{ let _said = Io.writeLine(reason) \}\n  \}\n  match withdraw(&mut account, 30) \{\n    case Ok(_) => \{ let _said = Io.writeLine(\"withdrew 30: \" + describe(&account)) \}\n    case Err(reason) => \{ let _said = Io.writeLine(reason) \}\n  \}\n  0\n\}\n```\n"},51  Chapter.Chapter{group: "examples", slug: "traits", title: "Traits", markdown: "# Traits\n\n```pudu\n// Traits\n// A trait names what a type can do, and dynamic lets one list hold different types.\nmodule Main\n\nimport Std.Io as Io\n\ntrait Describe \{\n  fn describe(self: &Self) -> Str\n\}\n\ntype Deer = \{ name: Str, heightCm: Int \}\n\ntype Bird = \{ name: Str, canFly: Bool \}\n\nimpl Describe for Deer \{\n  fn describe(self: &Self) -> Str \{\n    \"\{self.name\} stands \{self.heightCm\} cm tall\"\n  \}\n\}\n\nimpl Describe for Bird \{\n  fn describe(self: &Self) -> Str \{\n    if self.canFly \{ \"\{self.name\} flies\" \} else \{ \"\{self.name\} walks\" \}\n  \}\n\}\n\nfn main() -> Int \{\n  let animals: Array[dynamic Describe] = [\n    Deer\{name: \"Pudu\", heightCm: 40\},\n    Bird\{name: \"Condor\", canFly: true\},\n    Bird\{name: \"Rhea\", canFly: false\}\n  ]\n  for animal in animals \{\n    let _said = Io.writeLine(animal.describe())\n  \}\n  0\n\}\n```\n"},52  Chapter.Chapter{group: "examples", slug: "generics", title: "Generics", markdown: "# Generics\n\n```pudu\n// Generics\n// Type parameters, trait bounds, where clauses, type aliases, and a parameter that stands for a container.\nmodule Main\n\nimport Std.Io as Io\nimport Std.List as List\nimport Std.Order \{Ord\}\n\ntype Pair[A, B] = \{ first: A, second: B \}\n\ntype Scores = Map[Str, Int]\n\ntrait Scored \{\n  fn score(self: &Self) -> Int\n\}\n\ntype Player = \{ name: Str, points: Int \}\n\nimpl Scored for Player \{\n  fn score(self: &Self) -> Int \{ self.points \}\n\}\n\nfn swap[A, B](pair: Pair[A, B]) -> Pair[B, A] \{\n  Pair\{first: pair.second, second: pair.first\}\n\}\n\nfn best[T: Scored](items: &Array[T]) -> Option[T] \{\n  var found: Option[T] = None\n  for item in *items \{\n    found = match found \{\n      case Some(held) => if item.score() > held.score() \{ Some(item) \} else \{ Some(held) \}\n      case None => Some(item)\n    \}\n  \}\n  found\n\}\n\nfn middle[T](items: &Array[T]) -> Option[T] where T: Ord \{\n  let ordered = List.sorted(items)\n  if ordered.isEmpty() \{ None \} else \{ Some(ordered[ordered.length() / 2]) \}\n\}\n\ntrait Container[F[_]] \{\n  fn transformed[A, B](self: &F[A], change: fn(A) -> B) -> F[B]\n\}\n\ntype Both[T] = \{ left: T, right: T \}\n\nimpl Container[Both] for Both \{\n  fn transformed[A, B](self: &Both[A], change: fn(A) -> B) -> Both[B] \{\n    Both\{left: change(self.left), right: change(self.right)\}\n  \}\n\}\n\nimpl Container[Array] for Array \{\n  fn transformed[A, B](self: &Array[A], change: fn(A) -> B) -> Array[B] \{ self.map(change) \}\n\}\n\nfn lengths[F[_]](texts: &F[Str]) -> F[Int] where F: Container \{\n  texts.transformed(|text: Str| text.length())\n\}\n\nfn main() -> Int \{\n  let swapped = swap(Pair\{first: 1, second: \"one\"\})\n  let _swapped = Io.writeLine(\"swapped: \{swapped.first\} \{swapped.second\}\")\n\n  let players = [Player\{name: \"ada\", points: 36\}, Player\{name: \"grace\", points: 45\}]\n  match best(&players) \{\n    case Some(player) => \{ let _best = Io.writeLine(\"best: \{player.name\}\") \}\n    case None => \{ let _none = Io.writeLine(\"nobody played\") \}\n  \}\n\n  let _numbers = Io.writeLine(\"middle number: \{middle(&[9, 1, 5])\}\")\n  let _words = Io.writeLine(\"middle word: \{middle(&[\"b\", \"c\", \"a\"])\}\")\n\n  let scores: Scores = mapOf([(\"ada\", 3), (\"grace\", 4)])\n  let _scores = Io.writeLine(\"scores: \{scores\}\")\n\n  let sized = lengths(&Both\{left: \"pudu\", right: \"forest\"\})\n  let _both = Io.writeLine(\"lengths of a Both: \{sized.left\} and \{sized.right\}\")\n  let _array = Io.writeLine(\"lengths of an Array: \{lengths(&[\"a\", \"bb\", \"ccc\"])\}\")\n  0\n\}\n```\n"},53  Chapter.Chapter{group: "examples", slug: "compile-time", title: "Compile time and macros", markdown: "# Compile time and macros\n\n```pudu\n// Compile time and macros\n// A comptime fn computes a constant while compiling; a macro writes code where it is called.\nmodule Main\n\nimport Std.Io as Io\n\ncomptime fn powerOfTwo(exponent: Int) -> Int \{\n  var value = 1\n  for _ in 0..exponent \{\n    value = value * 2\n  \}\n  value\n\}\n\ncomptime fn squares(count: Int) -> Array[Int] \{\n  var found: Array[Int] = []\n  for n in 0..count \{\n    found = found.push(n * n)\n  \}\n  found\n\}\n\n// Computed by the compiler; the running program starts with the answers.\nconst BUFFER_SIZE: Int = powerOfTwo(12)\nconst SQUARES: Array[Int] = squares(8)\n\nmacro twice(value: expr) = value + value\n\nmacro squared(value: expr) = \{\n  let held = value\n  held * held\n\}\n\nmacro swap(left: ident, right: ident) = \{\n  let held = left\n  left = right\n  right = held\n\}\n\nmacro announced(body: block) = \{\n  let _started = Io.writeLine(\"-- starting\")\n  body\n\}\n\nfn main() -> Int \{\n  let _buffer = Io.writeLine(\"buffer size \{BUFFER_SIZE\}\")\n  let _squares = Io.writeLine(\"squares \{SQUARES\}\")\n\n  // An expr argument is one expression: squared!(1 + 2) is 9, not 1 + 2 * 1 + 2.\n  let _twice = Io.writeLine(\"twice!(21) = \{twice!(21)\}, squared!(1 + 2) = \{squared!(1 + 2)\}\")\n\n  // Names a macro introduces are its own: this held is untouched by swap! and squared!.\n  let held = \"mine\"\n  var first = 3\n  var second = 4\n  swap!(first, second)\n  let sum = announced!(\{ first + second \})\n  let _swapped = Io.writeLine(\"after swap! first=\{first\} second=\{second\}, sum \{sum\}, held is still \{held\}\")\n  0\n\}\n```\n"},54  Chapter.Chapter{group: "examples", slug: "testing", title: "Testing", markdown: "# Testing\n\n```pudu\n// Testing\n// A suite of checks with Std.Test: plain conditions, equality, options, results, groups, and tables of cases.\nmodule Main\n\nimport Std.Io as Io\nimport Std.Test as Test\nimport Std.Text as Text\n\nfn percentage(text: Str) -> Result[Int, Str] \{\n  let Some(value) = Text.wholeOf(text.trim()) else \{ return Err(\"'\{text\}' is not a number\") \}\n  if value < 0 || value > 100 \{ Err(\"\{value\} is out of range\") \} else \{ Ok(value) \}\n\}\n\nfn isLeapYear(year: Int) -> Bool \{\n  (year % 4 == 0 && year % 100 != 0) || year % 400 == 0\n\}\n\nfn main() -> Int \{\n  let parsing = Test.suite(\"percentage\", &[\n      Test.succeeded(\"a number in range\", &percentage(\"42\")),\n      Test.equals(\"spaces are ignored\", &percentage(\" 7 \"), &Ok(7)),\n      Test.errored(\"a word is refused\", &percentage(\"many\")),\n      Test.errored(\"above 100 is refused\", &percentage(\"101\"))\n    ])\n  let leapYears = [(2000, true), (1900, false), (2024, true), (2023, false)]\n  let years = Test.suite(\"leap years\", &Test.each(&leapYears, |row: (Int, Bool)| \"\{row[0]\}\", |row: (Int, Bool)| isLeapYear(row[0]) == row[1]))\n  let lookups = Test.suite(\"lookups\", &[\n      Test.present(\"a key that is there\", &mapOf([(\"ada\", 1)]).get(\"ada\")),\n      Test.absent(\"a key that is not\", &mapOf([(\"ada\", 1)]).get(\"grace\")),\n      Test.todo(\"unicode case folding\", \"not written yet\")\n    ])\n\n  let suite = Test.group(\"examples\", &[parsing, years, lookups])\n  for name in Test.names(&suite) \{\n    let _name = Io.writeLine(\"check: \{name\}\")\n  \}\n  // The lines name every failure, then the totals.\n  let report = Test.run(&suite)\n  for line in Test.lines(&report) \{\n    let _line = Io.writeLine(line)\n  \}\n  // Change a check above so it fails, and run again to see how a failure reads.\n  Test.status(&report)\n\}\n```\n"},55  Chapter.Chapter{group: "examples", slug: "data-formats", title: "JSON and CSV", markdown: "# JSON and CSV\n\n```pudu\n// JSON and CSV\n// Reading a JSON document into a record, writing one back, and totalling a CSV table by column.\nmodule Main\n\nimport Std.Csv as Csv\nimport Std.Io as Io\nimport Std.Json as Json\nimport Std.Map as Map\nimport Std.Option as Option\nimport Std.Text as Text\n\ntype User = \{ name: Str, age: Int \}\n\nconst DOCUMENT: Str = \"[\\\{\\\"name\\\": \\\"Ada\\\", \\\"age\\\": 36\\\}, \\\{\\\"name\\\": \\\"Grace\\\", \\\"age\\\": 45\\\}, \\\{\\\"name\\\": \\\"Nobody\\\"\\\}]\"\n\nconst SHEET: Str = \"name,team,points\\nada,red,12\\ngrace,blue,30\\n\\\"lin, jr\\\",red,8\\n\"\n\n// Each ? leaves with None when a field is missing or has the wrong kind.\nfn userFrom(value: &Json.Json) -> Option[User] \{\n  let name = Json.asText(&Json.field(value, \"name\") ?) ?\n  let age = Json.asInt(&Json.field(value, \"age\") ?) ?\n  Some(User\{name: name, age: age\})\n\}\n\nfn userJson(user: &User) -> Json.Json \{\n  Json.object(&[(\"name\", Json.Text(user.name)), (\"nextBirthday\", Json.Number(user.age + 1))])\n\}\n\nfn main() -> Int \{\n  let entries = match Json.decode(DOCUMENT) \{\n    case Ok(Json.List(items)) => items\n    case Ok(_) => \{ return 1 \}\n    case Err(problem) => \{\n      let _explained = Io.writeLine(Json.explain(&problem))\n      return 1\n    \}\n  \}\n  var users: Array[User] = []\n  for entry in entries \{\n    match userFrom(&entry) \{\n      case Some(user) => \{ users = users.push(user) \}\n      case None => \{ let _skipped = Io.writeLine(\"skipped an entry without a name and an age\") \}\n    \}\n  \}\n  let _read = Io.writeLine(\"read \{users.length()\} users\")\n  let _written = Io.writeLine(Json.encodePretty(&Json.list(&users.map(|user: User| userJson(&user)))))\n\n  let table = match Csv.parseTable(SHEET) \{\n    case Ok(held) => held\n    case Err(_) => \{ return 1 \}\n  \}\n  var totals: Map[Str, Int] = mapOf([])\n  for row in Csv.records(&table) \{\n    let team = Map.getOr(&row, \"team\", \"none\")\n    let points = Option.unwrapOr(Text.wholeOf(Map.getOr(&row, \"points\", \"0\")), 0)\n    totals = totals.insert(team, Map.getOr(&totals, team, 0) + points)\n  \}\n  let _totals = Io.writeLine(\"points by team: \{totals\}\")\n  let _names = Io.writeLine(\"names: \{Option.unwrapOr(Csv.column(&table, \"name\"), [])\}\")\n  0\n\}\n```\n"},56  Chapter.Chapter{group: "examples", slug: "html", title: "Building HTML", markdown: "# Building HTML\n\n```pudu\n// Building HTML\n// Std.Html builds a page as typed values, so text is escaped by construction and a bad link is refused.\nmodule Main\n\nimport Std.Html.Build as H\nimport Std.Io as Io\n\ntype Deer = \{ name: Str, heightCm: Int, note: Str \}\n\nfn row(deer: &Deer) -> H.Node \{\n  H.tr().holding([\n      H.td().says(deer.name),\n      H.td().class(\"number\").says(\"\{deer.heightCm\} cm\"),\n      H.td().says(deer.note)\n    ])\n\}\n\nfn page(herd: &Array[Deer]) -> H.Node \{\n  var rows = [H.tr().holding([H.th().says(\"Name\"), H.th().says(\"Height\"), H.th().says(\"Note\")])]\n  for deer in *herd \{\n    rows = rows.push(row(&deer))\n  \}\n  H.section().class(\"herd\").holding([\n      H.h1().says(\"The smallest deer\"),\n      H.p().holding([H.strong().says(\"\{herd.length()\}\"), H.span().says(\" deer, shortest first.\")]),\n      H.table().holding(rows)\n    ])\n\}\n\nfn main() -> Int \{\n  let herd = [\n    Deer\{name: \"Pudu\", heightCm: 40, note: \"lives in Chile & Argentina\"\},\n    Deer\{name: \"Muntjac\", heightCm: 50, note: \"<script>alert('barks')</script>\"\}\n  ]\n  // Each row on its own line. The note with a script in it arrives as text, not markup.\n  for deer in herd \{\n    let _row = Io.writeLine(H.render(&row(&deer)))\n  \}\n  let whole = H.render(&page(&herd))\n  let _page = Io.writeLine(\"the whole section is \{whole.length()\} characters and starts \{whole.take(40)\}\")\n\n  // A link whose target could run code is refused rather than written.\n  match H.a().hrefChecked(\"javascript:alert(1)\") \{\n    case Ok(_) => \{ let _kept = Io.writeLine(\"kept the link\") \}\n    case Err(_) => \{ let _refused = Io.writeLine(\"refused a javascript: link\") \}\n  \}\n  let _safe = Io.writeLine(H.render(&H.a().href(\"/docs/http\").says(\"Read about HTTP\")))\n  0\n\}\n```\n"},57  Chapter.Chapter{group: "examples", slug: "http", title: "HTTP routes", markdown: "# HTTP routes\n\n```pudu\n// HTTP routes\n// A server is built from values: handlers, routes, and a router answered here without opening a socket.\nmodule Main\n\nimport Std.Http as Http\nimport Std.Http.Server.Reply as Reply\nimport Std.Http.Server.Route as Route\nimport Std.Io as Io\nimport Std.Json as Json\nimport Std.Option as Option\n\nfn hello(request: Route.Request) -> Http.Response \{\n  let name = Option.unwrapOr(Route.queryParam(&request, \"name\"), \"world\")\n  Reply.text(200, \"Hello, \{name\}!\")\n\}\n\nfn user(request: Route.Request) -> Http.Response \{\n  match Route.param(&request, \"id\") \{\n    case Some(id) => Reply.jsonValue(200, Json.object(&[(\"id\", Json.Text(id)), (\"name\", Json.Text(\"user \{id\}\"))]))\n    case None => Reply.text(400, \"no user\")\n  \}\n\}\n\nfn routes() -> Route.Router \{\n  Route.routing(&[\n      Route.get(\"/hello\", hello),\n      Route.get(\"/users/:id\", user)\n    ])\n\}\n\n// What the server does with each request, without the network.\nfn ask(router: &Route.Router, target: Str) -> Http.Response \{\n  let request = Route.Request \{\n    message: Http.Request\{method: Http.Get, target: target, headers: [], body: \"\", binaryBody: None\},\n    path: Route.pathOf(target),\n    params: mapOf([]),\n    query: Route.queryOf(target),\n    peer: \"playground\"\n  \}\n  Route.dispatch(router, request)\n\}\n\nfn main() -> Int \{\n  let router = routes()\n  for target in [\"/hello\", \"/hello?name=Ada\", \"/users/7\", \"/nowhere\"] \{\n    let response = ask(&router, target)\n    let _said = Io.writeLine(\"GET \{target\} -> \{response.status.code\} \{response.body\}\")\n  \}\n  // The playground has no network, so this program never serves. Elsewhere,\n  // Std.Http.Server listens on a port with the same router: see /docs/http.\n  0\n\}\n```\n"},58  Chapter.Chapter{group: "examples", slug: "concurrency", title: "Concurrency", markdown: "# Concurrency\n\n```pudu\n// Concurrency\n// Async functions joined by a structured scope, workers mapping in parallel, and a bounded channel.\nmodule Main\n\nimport Std.Channel as Channel\nimport Std.Concurrent as Concurrent\nimport Std.Io as Io\n\nasync fn scoreFor(name: Str) -> Result[Int, Str] \{\n  if name.isEmpty() \{ Err(\"a name is needed\") \} else \{ Ok(name.length() * 10) \}\n\}\n\nfn slowSquare(n: Int) -> Int \{\n  var total = 0\n  for _ in 0..n \{\n    total = total + n\n  \}\n  total\n\}\n\nexport async fn main() -> Result[Int, Str] \{\n  // Tasks started in a scope cannot outlive it; awaiting gives the Ok value,\n  // and an Err leaves main through its own Result.\n  let total = async with scope \{\n    let first = scoreFor(\"ada\")\n    let second = scoreFor(\"grace\")\n    first.await + second.await\n  \}\n  let _scores = Io.writeLine(\"async total \{total\}\")\n\n  // Four workers share the work; the answers come back in the input's order.\n  let squares = match Concurrent.mapBounded(&[1000, 2000, 3000, 4000, 5000], 4, slowSquare) \{\n    case Ok(found) => found\n    case Err(_) => \{ return Err(\"a worker failed\") \}\n  \}\n  let _squares = Io.writeLine(\"worker squares \{squares\}\")\n\n  // A channel holds at most its capacity; drain reads what was sent, in order.\n  let messages: Channel.Channel[Str] = Channel.channel(8)\n  for word in [\"pudu\", \"huemul\", \"guanaco\"] \{\n    let _sent = Channel.send(&messages, word)\n  \}\n  let _closed = Channel.close(&messages)\n  match Channel.drain(&messages) \{\n    case Ok(words) => \{ let _words = Io.writeLine(\"received \{words\}\") \}\n    case Err(_) => \{ return Err(\"the channel failed\") \}\n  \}\n\n  // Try scoreFor(\"\") above: the Err leaves main, and the run reports it.\n  Ok(0)\n\}\n```\n"},59  Chapter.Chapter{group: "examples", slug: "time-and-randomness", title: "Time and randomness", markdown: "# Time and randomness\n\n```pudu\n// Time and randomness\n// Instants, durations, and dates from Std.Time, and seeded random numbers that repeat on every run.\nmodule Main\n\nimport Std.Io as Io\nimport Std.Random as Random\nimport Std.Time as Time\n\nfn main() -> Int \{\n  // A fixed instant, so the output is the same every run: 1 March 2024, noon UTC.\n  let launch = Time.instantOf(1709294400000)\n  let later = Time.add(&launch, &Time.plus(&Time.days(3), &Time.hours(5)))\n  match Time.toRfc3339(&later) \{\n    case Ok(text) => \{ let _later = Io.writeLine(\"three days and five hours later: \{text\}\") \}\n    case Err(problem) => \{ let _bad = Io.writeLine(problem) \}\n  \}\n  let _gap = Io.writeLine(\"the gap is \{Time.describe(&Time.between(&launch, &later))\}\")\n  match Time.parseDate(\"2024-02-29\") \{\n    case Ok(date) => \{ let _leap = Io.writeLine(\"a leap day parses: \{Time.renderDate(&date)\}\") \}\n    case Err(problem) => \{ let _bad = Io.writeLine(problem) \}\n  \}\n\n  // The clock is allowed too; it just answers differently each run.\n  let started = Time.elapsed()\n\n  // A generator is a value: each draw answers the next generator with the number.\n  // The same seed gives the same numbers, which is what a test wants.\n  let seeded = Random.fromSeed(2024u64)\n  let (afterDie, die) = Random.between(&seeded, 1, 6)\n  let (afterPick, animal) = Random.pick(&afterDie, &[\"pudu\", \"huemul\", \"guanaco\", \"vicuña\"])\n  let (_, shuffled) = Random.shuffle(&afterPick, &[1, 2, 3, 4, 5])\n  let _die = Io.writeLine(\"die \{die\}, animal \{animal\}, shuffled \{shuffled\}\")\n\n  let _took = Io.writeLine(\"that took \{Time.elapsed() - started\} ms\")\n  // Change the seed, or use Random.fromClock(), and run again.\n  0\n\}\n```\n"}60]61