GuideThe Silo HandbookGlossarysource

Source guide/A1-glossary.simd

1
2# Glossary
3
4A reference for the vocabulary used throughout the book. The first
5section covers Silo's language-level terminology and its system
6architecture. The second section covers the academic and research
7background behind Silo's design choices — useful if you want to
8follow footnotes into the literature.
9
10## Silo Concepts
11
12### Affine type
13
14A value that can be used at most once. After you consume it, it's
15gone. If you don't use it, the compiler drops it for you. Most
16values in Silo are affine. Contrast with *linear* (must be used
17exactly once) and *unrestricted* (use as many times as you want).
18
19### Algebraic effect
20
21A typed side effect that composes cleanly. "Algebraic" just means
22the effects combine according to simple laws (like addition) —
23`+Console +FileSystem` is the union, no special interaction. In
24practice: a function call where the implementation lives outside
25your program. The VM requests it, the host handles it. See
26[Effects, Totality, and Divergence](./10-effects.simd).
27
28### Arity variant
29
30A `/N`-suffixed variant of a built-in stack shuffler that operates
31on groups of `N` values rather than single values. `dup/2`
32duplicates the top pair; `swap/2` swaps the top two pairs; and so
33on. The bare `dup`/`drop`/`swap`/etc. are the arity-1 forms. See
34[Stack and Words](./02-stack-and-words.simd).
35
36### Aspect
37
38A cross-cutting concern with dynamic scoping. An aspect defines
39operations with default behaviour that can be overridden via
40`:with`. Think logging, tracing, metrics — behaviour you want to
41inject throughout a program without threading it through every
42function signature. See [Aspects](./11-aspects.simd).
43
44### Capability
45
46An effect that the host provides. Your code declares `+Console`,
47the host either provides a Console handler or doesn't. If it
48doesn't, compile error. Effects are capabilities — permissions to
49perform side effects.
50
51### Closure
52
53See [Quotation](#quotation). "Closure" is the Rust/ML name for the
54same construct; Silo calls it a quotation by tradition, but the
55two terms refer to the same thing: a block of code that captures
56bindings from its enclosing scope.
57
58### Concatenative
59
60A style of language where programs are built by *composing* words
61rather than applying named functions to named arguments. Silo,
62Forth, Factor, and Joy are concatenative. Every word reads from
63and writes to a shared stack; writing two words next to each
64other composes their effects. See [Welcome](./01-welcome.simd) and
65[Stack and Words](./02-stack-and-words.simd).
66
67### Constraint block
68
69The `{ (Trait Type) }` syntax after a signature. Restricts what
70types a generic function accepts: `{ (Eq a) (Display a) }` means
71"a must be equatable and displayable."
72
73### Dependent type
74
75A type that depends on a value. `(Vec Int | 5)` is a vector of 5
76integers — the `5` is a value that's part of the type. The
77compiler checks these at compile time. See
78[The Type System](./06-types.simd).
79
80### Derive list
81
82The `[Display Eq Ord]` syntax on type declarations. Tells the
83compiler to auto-generate trait implementations for the type.
84On newtypes, `[*]` means "derive every trait the wrapped type
85derives" and `-TraitName` opts out of a specific one — e.g.
86`[* -Display]` inherits everything except `Display`.
87
88### Divergence
89
90The `+Div` effect, carried by any word whose termination the
91compiler cannot prove statically. Silo is total by default;
92marking a word with `+Div` is how you opt into allowing
93non-termination. Callers see `+Div` in the word's signature and
94propagate it. See
95[Effects, Totality, and Divergence](./10-effects.simd).
96
97### Effect annotation
98
99The `+Effect` syntax after a signature:
100`:fn greet ( Str -> ) +Console`. Declares that this function
101uses the Console capability.
102
103### Effect handler
104
105The host-side (typically Rust) implementation of a declared
106effect. When silo code runs an effectful operation like `print`,
107the abstract machine doesn't perform I/O directly — it hands the
108request to the host, which dispatches to the effect handler
109registered for that effect. See [Welcome](./01-welcome.simd) and
110[Effects, Totality, and Divergence](./10-effects.simd).
111
112### Effect row
113
114The `+Foo +Bar …` tail on a stack-effect signature, listing the
115effects the word may perform. Effects are tracked statically and
116propagate up the call graph: a word that calls a `+Console` word
117must itself declare `+Console` (or handle it). See
118[Effects, Totality, and Divergence](./10-effects.simd).
119
120### Exhaustiveness
121
122The compile-time check that every possible value of the scrutinee
123is covered by some arm of a `:match`, `:if-let`, or `:let`.
124Missing cases are a compile error. See
125[Control Flow](./03-control-flow.simd) and
126[Pattern Matching](./08-pattern-matching.simd).
127
128### Existential type
129
130A type where you know the trait but not the concrete type.
131`Display` in a type position means "some value that implements
132Display, but I don't know what type it is." The compiler uses
133dynamic dispatch (vtable) for these.
134
135### Forward propagation
136
137How Silo's type checker works. It starts at the beginning of a
138function, tracks what's on the stack, and walks forward through
139each word, updating the stack types as it goes. Contrast with
140Hindley-Milner inference which solves constraints globally.
141
142### Higher-kinded type (HKT)
143
144A type that takes another type as a parameter, where the
145parameter itself takes parameters. `Option` is kind `* -> *`
146(takes a type, produces a type). `HashMap` is kind `* -> * -> *`.
147Lets you write traits like `Mappable` that work on any container,
148not just specific ones.
149
150### Higher-order function
151
152A word or method that takes a [quotation](#quotation) as one of
153its arguments. `.map`, `.filter`, `.fold`, `.for-each`, `while`,
154and `times` are all higher-order. See
155[Quotations and Higher-Order Functions](./04-quotations.simd).
156
157### Host
158
159The runtime environment Silo runs under. Typically a Rust program
160that builds a frontend, compiles source, and drives the abstract
161machine. The host declares which effects it supports; silo code
162that uses only those effects is portable across any host that
163provides them. See [Welcome](./01-welcome.simd).
164
165### Inherent impl
166
167Methods defined directly on a type, not associated with any
168trait: `:impl Foo .distance ( Foo -> F64 ) ... :end`. These
169belong to the type itself. Distinct from *trait impls*
170(`:impl (Eq Foo)`) which implement a trait for a type.
171
172### Init block
173
174A `:init ... :end` declaration that runs before `:main`. Can
175create named words (module-scoped runtime constants) and register
176aspect handlers. `:deinit` runs after main for cleanup.
177
178### Kind
179
180The "type of a type." `Int` has kind `*` (it's a concrete type).
181`Option` has kind `* -> *` (it's a type constructor that takes
182one argument). The compiler checks that type constructors are
183applied to the right number of arguments.
184
185### Linear type
186
187A value that must be used exactly once. In Silo, values on the
188stack are linear by default — each stack slot has exactly one
189owner. `dup` introduces sharing (making copies affine). `drop`
190explicitly discards.
191
192### Local binding
193
194The `pop->` and `peek->` forms for giving a stack value a name.
195`pop-> name` pops the top of the stack and binds it; `peek->
196name` copies the top and leaves it on the stack. Both are
197lexically scoped to the enclosing word or quotation. See
198[Stack and Words](./02-stack-and-words.simd).
199
200### Monomorphisation
201
202Compiling a generic function into concrete type-specific
203versions. When you call `sort` on integers, the compiler
204generates a version of `sort` specialised for integers with
205direct calls to the integer comparison function. No runtime
206dispatch overhead.
207
208### Never
209
210The **bottom type** — a primitive with no values. An
211expression of type `Never` provably doesn't return, so code
212downstream is unreachable and the compiler lets it have any
213type through vacuous coercion. Used by `panic`, `.exit`, and
214any operation that doesn't return. See
215[The Type System](./06-types.simd#unit-and-never) and
216[Pattern Matching](./08-pattern-matching.simd) for the
217isomorphism rules that make `Never` useful in return
218positions.
219
220### Newtype
221
222A `:type` declaration that creates a distinct type wrapping an
223existing one: `:type UserId Int`. Zero runtime cost but the
224compiler treats `UserId` and `Int` as different types. The
225escape hatch for type-level control.
226
227### Orphan impl
228
229A trait implementation defined in a package that owns neither
230the trait nor any of the types involved. Must be explicitly
231imported via `:impl` in a `:use` block. Contrast with type-crate
232and trait-crate impls, which come automatically when their type
233or trait is in scope.
234
235### Output variadic
236
237A calling convention where a word produces a statically-known
238*number* of outputs and pushes that count last so callers can
239consume it. `.collect` uses output variadics to turn a quotation
240that pushes `n` values into a `Vec` of exactly `n` elements —
241the length ends up in the Vec's type. See
242[Quotations and Higher-Order Functions](./04-quotations.simd)
243and
244[Variadics and Reflection](./19-variadic-and-reflection.simd).
245
246### Perceus
247
248The reference counting algorithm Silo uses (from Koka). The
249compiler inserts dup/drop operations, then optimises them away
250via drop specialisation and reuse analysis. The goal: most
251values are unique (refcount 1) and can be mutated in place.
252
253### Predicate
254
255A compile-time-only type constraint with no runtime
256representation. `:pred Positive ( (Int n) ) { (n 0 ">") }`. The
257compiler checks it; the runtime never sees it. Inspired by
258theorem provers.
259
260### Quotation
261
262A block of code as a value: `[ 2 * ]`. Has a type like
263`[ Int -> Int ]`. Can be passed around, stored, and called.
264Silo's version of anonymous functions / closures. See
265[Quotations and Higher-Order Functions](./04-quotations.simd).
266
267### Region
268
269A chunk of memory that's allocated and freed as a unit. Each
270function call gets its own region. When the function returns,
271the whole region is freed. Faster than individual allocations.
272
273### Row variable
274
275A type variable that represents "the rest of the stack." In
276`[ ..s Int -> ..s Int Int ]`, `..s` is a row variable — the
277quotation works on any stack that has an `Int` on top, leaving
278everything below untouched. See
279[Quotations and Higher-Order Functions](./04-quotations.simd).
280
281### Sans-IO
282
283The VM design principle. The VM never performs I/O. It's a pure
284state machine: given an input, it produces outputs (including
285effect requests). The host performs actual I/O. This makes the
286VM deterministic, testable, and sandboxed. See
287[Welcome](./01-welcome.simd).
288
289### Scoped impl
290
291The visibility model for trait implementations. Type-crate impls
292(same package as the type) and trait-crate impls (same package
293as the trait) come into scope automatically when the type or
294trait is imported. Orphan impls (from a third package) require
295explicit `:impl` import. Silo has no orphan rule — anyone can
296write any impl — but orphans must be explicitly brought into
297scope.
298
299### Specialisation
300
301When multiple trait impls match (a concrete one and a blanket
302one), the more specific (concrete) impl wins.
303`(From Thing Widget)` beats `(From t v) { (v Default) }`.
304
305### Stack
306
307The single data stack every word reads from and writes to. Typed
308at compile time: the checker knows the shape of the stack at
309every point in the source. Displayed by the REPL with
310floor/ceiling brackets, top on the right: `⌊1 2 3⌉` means the
311top of the stack is `3`. See
312[Stack and Words](./02-stack-and-words.simd).
313
314### Stack effect
315
316The type of a word: `( inputs -> outputs )`. Describes what a
317word consumes from the stack and what it produces.
318`( Int Int -> Int )` means "pop two ints, push one int." See
319[Stack and Words](./02-stack-and-words.simd).
320
321### Stack shuffler
322
323A built-in polymorphic word for rearranging the top few values
324on the stack without touching their types: `dup`, `drop`,
325`swap`, `over`, `rot`, `nip`. Useful in short pipelines; for
326anything longer, reach for `pop->` or `peek->` because named
327bindings read better. See
328[Stack and Words](./02-stack-and-words.simd).
329
330### Total
331
332A word is total if the compiler can prove it terminates on
333every input. Silo words are total by default — non-total words
334must carry the `+Div` effect. Totality is preserved through
335composition: calling a total word doesn't make your word
336non-total, but calling a `+Div` word does. See
337[Control Flow](./03-control-flow.simd) and
338[Effects, Totality, and Divergence](./10-effects.simd).
339
340### Trait
341
342An interface definition. Declares a set of operations that
343types can implement:
344`:trait Eq self .eq ( self self -> Bool ) :end`. A *trait impl*
345(`:impl (Eq Point) ...`) implements a trait for a specific
346type. Not to be confused with an *inherent impl*
347(`:impl Point ...`) which adds methods to a type without a
348trait. See [Traits](./09-traits.simd).
349
350### Unit
351
352A primitive type with exactly one value, written `unit`. The
353intrinsic word `unit` has signature `( -> Unit )` and pushes
354that value onto the stack. Distinct from an empty output side
355in a stack effect — `( Str -> )` produces zero slots;
356`( Str -> Unit )` produces one slot holding `unit`. Useful in
357generic contexts like `(Result Unit err)` where you need a
358type parameter but have no meaningful value to carry. See
359[The Type System](./06-types.simd#unit-and-never).
360
361### Word
362
363A function, in the Forth tradition. Silo calls them words
364mostly because "function" already means something in algebraic
365terms and "word" is the name the concatenative family has used
366for fifty years. Declared with `:fn`. See
367[Welcome](./01-welcome.simd) and
368[Stack and Words](./02-stack-and-words.simd).
369
370## Academic and Research Background
371
372### Algorithm W
373
374The classic type inference algorithm for Hindley-Milner type
375systems (Milner 1978). Walks the syntax tree, generates fresh
376type variables, unifies constraints. Produces principal types.
377λ◦ uses a variant of this for concatenative type inference.
378
379### De Bruijn index
380
381A way to represent variable binding without names. Instead of
382`λx. λy. x`, you write `λ. λ. 1` (the variable bound 1 level
383up). Avoids naming conflicts. Used internally by Reliquary's
384core calculus.
385
386### Drop specialisation
387
388A Perceus optimisation. Instead of a generic `drop(x)` that
389checks the type at runtime, the compiler generates a `drop`
390specialised for each constructor: "if unique, free the Cons
391node and drop its children; otherwise just decrement."
392Eliminates most RC operations on the fast path.
393
394### Evidence passing
395
396Koka's compilation technique for effects. Instead of capturing
397continuations, handlers in scope are passed down the call chain
398as an "evidence vector." Each function receives the evidence it
399needs to dispatch effect operations. Compiles to efficient C
400without a runtime.
401
402### FBIP (Functional But In-Place)
403
404A programming paradigm from Koka/Perceus. If your data is
405unique (refcount 1), purely functional operations like `map`
406execute via in-place mutation. The compiler guarantees this
407through reuse analysis. You write functional code; it runs
408imperatively.
409
410### Hindley-Milner (HM)
411
412The standard type system for ML-family languages. Key
413properties: parametric polymorphism (generics),
414let-polymorphism (generalisation at let-bindings), complete
415type inference (you never need to write type annotations). λ◦
416adapts HM for concatenative languages.
417
418### Infinitary unification
419
420When unifying two type sequences that both contain sequence
421variables in arbitrary positions, there may be infinitely many
422solutions. λ◦ avoids this by restricting sequence variables to
423the leftmost position, making unification unitary (exactly one
424most general solution).
425
426### Lambda-circle (λ◦)
427
428Kleffner's formal calculus for typed concatenative languages.
429Expressions are lists of words. Types are stack effects `i → o`
430with sequence variables. Proved sound with a complete
431inference algorithm.
432
433### Linear resource calculus (λ₁)
434
435The formal system used to prove Perceus correct. Based on
436linear logic — every resource (reference) must be consumed
437exactly once. Perceus is proved sound (never drops a live
438reference) and garbage-free (never retains a dead one) in this
439calculus.
440
441### Mechanisation
442
443Encoding a formal proof in a machine-checked theorem prover
444(Isabelle, Coq, Lean). If the prover accepts it, the proof is
445correct by construction. Watt mechanised WebAssembly's type
446soundness, finding real bugs the paper proofs missed.
447
448### Modular implicits
449
450OCaml's approach to scoped typeclass instances. Instead of
451global resolution (Haskell) or explicit dictionary passing (ML
452functors), instances are resolved from what's in scope.
453Directly influenced Silo's scoped impl design.
454
455### Pi type (Π)
456
457Dependent function type. `Π(x:A). B(x)` means "a function that
458takes an `x` of type `A` and returns a value whose type depends
459on `x`." The dependent version of `A → B`. Used by Reliquary's
460core calculus.
461
462### Polycyclic monoid
463
464The algebraic structure that Pöial's stack effects form. A
465monoid (has identity and associative composition) with inverses
466(swap inputs and outputs) and a zero element (type error).
467Proved isomorphic to stack effects by Nivat & Perrot (1970).
468
469### Principal type
470
471The most general type that can be assigned to an expression.
472If an expression has principal type `∀a. a → a`, then every
473other valid type for it (like `Int → Int`) is an instance of
474the principal type. HM inference guarantees principal types.
475
476### Progress
477
478Half of type soundness. "A well-typed program is never stuck."
479Either it's finished (a value), it's an error (Trap), or it
480can take a step. If progress holds, well-typed programs always
481do something — they don't silently freeze.
482
483### Preservation
484
485The other half of type soundness. "If a well-typed program
486takes a step, the result is still well-typed." Types are
487preserved across evaluation steps. Together with progress:
488well-typed programs don't go wrong.
489
490### Rank-n polymorphism
491
492The ability to have polymorphic types nested inside other
493types. Rank-1: `∀a. a → a` (the ∀ is at the outside). Rank-2:
494`(∀a. a → a) → Int` (a function that takes a polymorphic
495function). Typing `call` in a concatenative language needs at
496least rank-2. Silo sidesteps this via forward propagation
497instead of full HM inference.
498
499### Refinement type
500
501A type plus a predicate: `{ x:Int | x ">" 0 }`. The type checker
502(or an SMT solver) verifies the predicate holds. Helmholtz
503uses refinement types on Michelson stacks. Silo's predicates
504are a restricted form of refinement types.
505
506### Resurrection hypothesis
507
508From Lean 4's "Counting Immutable Beans." When you want to
509construct a value, there's usually a recently deconstructed
510value of the same size available for reuse. In concatenative
511code, this is even more true — "pop old, push new" is the
512dominant pattern.
513
514### Reuse analysis
515
516A Perceus optimisation. When a `match` destructures a value
517and the branch constructs a new value of the same size, the
518compiler pairs them. If the original is unique at runtime, its
519memory is reused directly without allocation.
520
521### Row polymorphism (academic)
522
523A form of polymorphism over extensible records or rows.
524`⟨exn, div | μ⟩` means "a row containing exn and div, plus
525whatever else μ contains." Used by Koka for effects and
526conceptually by Silo for stack effects (row variables = "rest
527of the stack").
528
529### Sequence variable
530
531λ◦'s term for a type variable that ranges over sequences of
532types, not just single types. Written `ᾱ` (with an overline).
533The stack-polymorphism mechanism: `ᾱ Int → ᾱ Int Int` means
534"whatever's on the stack, plus an Int on top."
535
536### Sigma type (Σ)
537
538Dependent pair type. `Σ(x:A). B(x)` means "a pair where the
539type of the second element depends on the value of the first."
540The dependent version of `A × B`. Reliquary encodes stacks as
541nested Σ-types.
542
543### Soundness
544
545A type system is sound if well-typed programs never "go wrong"
546— never reach an undefined state. Formally: progress +
547preservation. If a type system is sound, the types are
548trustworthy. If unsound, the types can lie.
549
550### SpecTec
551
552WebAssembly's DSL for authoring the formal specification. A
553single source generates the spec document, a reference
554interpreter, and (planned) theorem prover mechanisations.
555Adopted by the Wasm Community Group in 2025.
556
557### Stack-polymorphic
558
559An instruction whose entire stack effect is unconstrained. In
560WebAssembly, `unreachable` and `br` are stack-polymorphic —
561after an unconditional branch, the dead code can have any
562type. Different from value-polymorphic (like `drop`, which
563works on any single value but has a fixed stack shape).
564
565### Substructural type system
566
567A type system that restricts how values can be used. Linear:
568exactly once. Affine: at most once. Relevant: at least once.
569Ordered: in order. Silo combines ordered (stack discipline)
570with affine (compiler-managed dup/drop).
571
572### Unification
573
574Finding a substitution that makes two types equal. To unify
575`(List a)` with `(List Int)`, substitute `a = Int`. The core
576operation in type inference. Silo's forward propagation does a
577form of unification at each word boundary.
578
579### Unitary unification
580
581When a unification problem has at most one most general
582solution. λ◦ restricts sequence variables to the leftmost
583position to ensure unification is unitary. Without this
584restriction, sequence unification can have infinitely many
585solutions.
586
587### Value-polymorphic
588
589An instruction that works on any single value type but has a
590fixed stack shape. WebAssembly's `drop` is value-polymorphic:
591it pops one value of any type. Different from stack-polymorphic
592(where the entire stack effect is unconstrained).
593
594### Vtable
595
596A table of function pointers used for dynamic dispatch. When
597you have an existential type (you know the trait but not the
598concrete type), the vtable maps trait operations to the correct
599implementation for the hidden concrete type. Created at the
600point where a concrete value is coerced to an existential.