All pages
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
| path | resolves to |
|---|---|
sexpgpu/nn, sexpgpu/optim | the standard modules; see nn and optim. Anything else under sexpgpu/ is E-EVAL-033 |
./name.sx, ../dir/name.sx | a file, relative to the directory of the file holding the require, never to a project root or the working directory |
| anything else | E-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
requirenames at least one definition. Naming something the file does not define isE-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 isE-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,modelortrain-loader, is read by the compiler and is used. - Imported names are not re-exported.
requireruns at module top level, including inside a top-levelprognor a macro expansion. In a local scope it isE-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.