S-exp GPU
All pages
Docs · The run fileMarkdown

Modules and require

Every file is a module with its own scope. require imports named definitions from a standard module compiled into the binary or from a file next to yours.

(require "sexpgpu/nn" cross-entropy gpt)       ; a standard module
(require "sexpgpu/optim" adamw warmup-stable-decay)
(require "../lib/mine.sx" my-gpt)              ; a file, relative to this one

Resolution

pathresolves to
sexpgpu/nn, sexpgpu/optimthe standard modules; see nn and optim. Anything else under sexpgpu/ is E-EVAL-033
./name.sx, ../dir/name.sxa file, relative to the directory of the file holding the require, never to a project root or the working directory
anything elseE-EVAL-032: a path must start with ./ or ../

A file is loaded once per compilation, by canonical path. A cycle is E-EVAL-030, a missing file E-EVAL-031. Because paths are relative to the file, every command works from any working directory.

Scope

A file sees three things: the prelude, what it defines, and the names its requires list. It sees nothing a library required in turn.

  • Every top-level definition of a file can be imported; there is no export list. Generated top-level definitions (from a macro) can be imported too.
  • A require names at least one definition. Naming something the file does not define is E-EVAL-035, and the fix is the nearest name it does.
  • A name is bound once per file. Two imports of one name, from one module or two, or an import and a local definition, are E-EVAL-036.
  • Every import is used. A name the file writes nowhere but in its requires is E-EVAL-037; take it out. Writing it anywhere counts, including on a branch the selected knobs skip, so an optimizer imported for (if (= opt :muon) ...) is used under every selection. A contract name the run file imports, model or train-loader, is read by the compiler and is used.
  • Imported names are not re-exported.
  • require runs at module top level, including inside a top-level progn or a macro expansion. In a local scope it is E-EVAL-034.
  • Import a name before writing a function or quoted datum that uses its identity; imports do not rewrite symbols already constructed. See macros.

A library macro's expansion keeps the library's symbol identities, so it can call the library's private helpers without the caller importing them. The symbols it writes are looked up in the library and then the prelude, never in the requiring file: a name only the requiring file defines is E-EVAL-003, and the message names the library. See macros and symbols.

Writing a library

A library is a plain .sx file that your runs require. It can hold models, schedules and constants shared by several runs, and it can require sexpgpu/nn for the generic parts:

;;; lib/mine.sx
(require "sexpgpu/nn" rmsnorm linear)

(defvar init-std 0.02)

(defmodel my-gpt (&key vocab layers dim) ...)

A library can also carry diagnostics for its models, off until a run selects them; see writing diagnostics.

A bundle flattens every required file into files/deps/ and rewrites the paths; see bundle.

Related: the run file, the prelude.