Skip to content

Analyse .tmc completeness: what can a routine only say in prose? #121

Description

@mellonis

.tmc can declare a fair amount about a program — alphabets and tape typing, routine and graph signatures, writes/preserves contracts with footprint inference, volatile tapes, [deprecated], and, once the binding arc lands (#95, #118), state parameters as exits, noreturn, named maps and alphabet import. The question this issue asks is the one #95 deliberately did not: is that everything a library author and a large program need, or are there facts about a routine that the language can only state in prose? Like #95 this is an analysis, not a fix — verdicts per line, and a sketch for anything judged worth adding.

The starting evidence is again the standard library's own header, which says of its doc lines: "The ? lines on each entity are its normative contract, including where the head sits on entry and on exit." A normative contract that lives only in prose is the thing to look at first.

Lines of inquiry

1. Head position is part of every stdlib contract and is machine-invisible.

Every std routine documents where the head must be on entry and where it rests on exit ("On entry the head is on the number (any cell up to and including its '$'); on exit it rests on that '$'"). Nothing checks it: not the compiler, not a lint, and not the testing library #30 will become, because the fact has no representation. This is the failure mode of real library use — calling plusOne with the head one cell off — and the footprint engine already walks bodies for writes. Determine what a head clause would have to say to be checkable (entry precondition as a glyph set the head must be on; exit postcondition as a glyph set, or same/moved relative to entry; per tape), whether inference can confirm it the way it confirms writes (the same over-approximation caveat for substitution writes applies), and whether it belongs in the interface section and headers so a caller's footprint can use it.

2. A routine generic over its alphabet.

goToEnd-shaped behaviour depends on the blank and nothing else, yet a routine is typed by one concrete alphabet and reuse over another goes through a map. Index binding already gives de-facto duck typing, but there is no way to declare "this routine needs only the blank and these two symbols; anything else is opaque and passed through". Determine whether an alphabet parameter on a signature (routine r<A>(tape t: A) with a required-glyph constraint) is expressible on top of the composition engine — the callee's rows would be written against required symbols plus a wildcard for the rest — or whether index binding plus the item-4 warning from #95 is the honest limit.

3. Named glyph sets.

'0'..'9' is respelled in every pattern that needs it, in the stdlib and in rpnhex.tmc. A declaration (set digits = { '0'..'9' }) usable in pattern cells, write vectors and contract clauses would name the semantics once. Small; decide whether it earns its keyword, and how it interacts with ranges, as bindings and folds.

4. Trap behaviour as part of the interface.

noreturn states that a routine never executes ret; nothing states whether it can leave by a trap (UnmappedRead/UnmappedWrite/NoTransition). Today that is the compile-time lint state-may-trap, which a library consumer never sees. Determine whether "never traps" (or the set of traps a routine may raise) is a fact worth carrying as a clause and in the interface section, and whether the existing analysis behind state-may-trap can back it.

5. Representations.

"A number in the bare representation" is a convention described in a namespace comment; named maps and alphabet import (from #95) give half of it, the alphabet. The other half — the shape invariant of the tape — may belong to the testing library rather than to types. Settle which, so the question stops recurring.

Method

Not by argument. Three probe programs, each written against the current language plus the #95 design, each either written without friction or stopping at the missing word:

  • a library over two representations whose head preconditions are checked rather than documented (line 1);
  • one routine generic over its alphabet, used over three different alphabets (line 2);
  • decimal arithmetic over a rich alphabet, where named sets are either needed or provably not (line 3).

The probes live under docs/superpowers/ while the analysis runs; whatever survives becomes an example or a stdlib routine.

What a good outcome looks like

A written verdict per line — inherent / worth adding / not worth adding — with the probe that decided it, and for anything judged worth adding, enough of a sketch to become its own issue. Line 1 is the one that changes what a contract is; lines 2–5 mostly need settling.

Docs that bound the current language: docs/tmt/language.md (contract clauses, substitution), docs/tmt/stdlib.md, the ? lines throughout crates/turing-machine/src/stdlib/std.tmc, and the binding-arc spec docs/superpowers/specs/2026-09-13-issue-95-binding-analysis.md for what the language will already have.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions