Skip to content

safe.ts: simplify again, same output - #1945

Merged
nicolas-abril merged 7 commits into
bendlang:mainfrom
nicolas-abril:refactor/safe-simplify-2
Oct 29, 2026
Merged

nicolas-abril merged 7 commits into
bendlang:mainfrom
nicolas-abril:refactor/safe-simplify-2

Conversation

@nicolas-abril

@nicolas-abril nicolas-abril commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

A second simplification pass over safe.ts, with the same output. It makes room for #1896 under safe.ts's 24000-token cap. safe.ts goes from 23289 to 22875 ttok. #1896's η commits, picked onto this branch, apply cleanly and land at 23952.

What

Helpers:

  • lams2(q, l, b) builds λt => λf => b at q, a default arm's binders. swi's empty default wrote these λs out by hand; now both of swi's cases build them. The default arm passes copies(e, q, b, [l, l + 1]) as q. It replaces pair_lams.
  • uses had one caller left, tree's rebuild check, which now reads o_uses itself.
  • spec_val had one caller, args, and is inlined.
  • The out-of-scope fixed point in safe_pass finds each def's names the first time it asks, then reuses them, instead of walking the def again on every pass. As before, it walks nothing when no def is out of scope.
  • safe_book and safe_pass share an Out type.

Shorter forms:

  • term's ∀ case builds its node in one literal, A before B as before. Switch cases keep their braces.
  • let_term, rwt_term and adt_emit use their one-use locals in place, in the same order.
  • tele_open's return type is inferred from the record it builds.
  • adt_emit applies D.arms to the tag with apps, as everywhere else.
  • def_emit's no-model reason goes straight into ?? oos(..), which builds it only when no model is found; the else branch it covers is parenthesized. Its type goes into e.out without a local.
  • kernel_bin reads $BENDTT directly, and its comment names LEAN_VERSION instead of repeating it.

Comments:

  • As in bend.ts and comp.ts, which comment 3% and 5% of their functions, a comment that only restates its code goes. That covers 19 one-liners, including those over vr, tkey, node, fill, wnf, all_of, ctr_term, o_refs, apps and alls. Comments that give a reason, a contract or an encoding stay, or move into the code:
    • mentions takes a B.LTerm, so passing an unlowered term (whose binders hide their variables in closures) is a type error;
    • no_ctr is no_ctr_left: every constructor matched away, not a datatype declared with none;
    • mats says h runs from the last label to the first, and that what h names goes out in that order.
  • safe_book's comment points to the header for the out-of-scope rule instead of repeating it; kind's and run_read's say the same in fewer words.

Checks

  • -o on all 1795 files of tests/, main (0a41eea) against this branch: the same BendTT and the same messages on every file.
  • bunx tsc -p bend2/pack: no errors in safe.ts.
  • bun gates/_run.ts: repo 54 / 54, test 1782 / 1782, perf 124 / 124, ping 80 / 81 (pass).
  • bun gates/safe.ts tests: the same verdict as main on every file: agree 1143, unsafe 142, bend2 rejects 507, out of scope 3, false reject 0, timeout 0, infrastructure 0.

🤖 Generated with Claude Code

nicolas-abril and others added 6 commits October 29, 2026 17:45
… applies through apps; def_emit's reason is in its oos

- pair(q, l, b) is λt => λf => b at q: swi's empty default and its default
  arm both build it, the latter at copies(e, q, b, [l, l + 1])
- uses had one caller left, tree's rebuild check, which reads o_uses itself
- adt_emit's D applies D.arms to the tag with apps, as everywhere else
- def_emit's no-model reason goes straight into ?? oos(..), which builds it
  only when no model is found

Same -o output on all 1795 files of tests/; safe.ts 24053 -> 23935 ttok, under its cap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ined; single returns where the branches only pick a value

- a switch case that only returns goes on one line, as o_uses and o_show
  already do (term, model_at); term's ∀ builds its node in one literal
- spec_val (one caller, args) is inlined; Regroup carries its key as its
  message; o_refs returns its names as an array
- scope_hide, convoy_bind, tree's tail and mentions return one expression;
  put picks set or add with a ternary
- safe_book and safe_pass share an Out type; def_emit pushes its type
  without a local; kernel_bin reads $BENDTT directly
- run_read's comment keeps the symptom, not where it was seen

Same -o output as main on all 1795 files of tests/; 23289 -> 22899 ttok
with the commit before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…wt_term, adt_emit and tele_open say the same shorter

- the one-line switch cases go back to their braced blocks; term's ∀ keeps
  its one literal inside its block
- pick and group_new return one expression
- let_term, rwt_term and adt_emit use their one-use locals in place
- tele_open's return type is inferred from the record it builds
- safe_pass's why reads bad's entry with !
- kernel_bin's comment names LEAN_VERSION instead of repeating it

Same -o output as main on all 1795 files of tests/; 22908 ttok.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scope_hide, convoy_bind, mentions, pick, put and group_new are main's again,
tree keeps its two early returns, and o_refs returns early for a Ref.

Same -o output as main on all 1795 files of tests/; 22999 ttok.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
As bend.ts and comp.ts, which comment few of their functions: the
one-liners over vr, Scope, Safe, tkey, node, fill, wnf, all_of, mentions,
no_ctr, ctr_term, o_refs, apps, alls, mats, scope_var, typed, QS and fresh
said what the name and the code already say. Comments that give a reason,
a contract or an encoding stay. safe_book's points to the header for the
out-of-scope rule, kind's and run_read's say the same in fewer words.

Comments only; 22762 ttok.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… Regroup keeps its key; lams2; ?? scoped visibly

- o_refs fills one shared set again: the array version copied every name
  once per level, quadratic in a term's depth
- the out-of-scope fixed point finds each def's names the first time it
  asks, then reuses them, instead of walking the def again every pass;
  still only once something is out of scope, as before (a book with
  nothing out of scope walks no term: string_literal_long's is deep enough
  to overflow the stack)
- Regroup carries its key in a typed field again, not in its message
- swi's λ pair builder is lams2; the default's binder tuple is pair again
- def_emit parenthesizes the else branch that ?? oos(..) covers
- run_read's comment says again where the pipe loss was seen, which is
  why main.ts runs clang --version through it

Same -o output and verdict table as main on all 1795 files of tests/;
22844 ttok.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Lorenzobattistela Lorenzobattistela self-assigned this Oct 29, 2026
…; mats says which way h runs

The review found three removed comments that held a contract, not a
restatement. Each now lives where the code keeps it:

- mentions takes a B.LTerm, so passing an unlowered term (whose binders
  hide their variables in closures) is a type error, not a comment to read
- no_ctr is no_ctr_left: a datatype whose constructors are all matched
  away, which a reader could take for one declared with none
- mats says h runs from the last label to the first, and that what h names
  goes out in that order (adt_emit's and group_emit's arms name items)

Same -o output as main; 22875 ttok.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nicolas-abril
nicolas-abril merged commit cf1332e into bendlang:main Oct 29, 2026
1 check passed
nicolas-abril added a commit to nicolas-abril/bend that referenced this pull request Oct 29, 2026
As bendlang#1945 did for the rest of the file: eta_finite's and datum's comments
say the same in fewer words, size's keeps only that a nat counts as its
value, embeds' drops what seen does, and eta's (λy => t(y)) went.

Comments only; 23900 ttok.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants