Skip to content

BendTT fits ∀s by their parts, as bend2's LE does, so the kernel, not safe.ts, fits Nat -> Kind(&2) to Nat -> Type - #1344

Merged
nicolas-abril merged 2 commits into
kernel-kind-termsfrom
kernel-all-fits
Oct 5, 2026
Merged

nicolas-abril merged 2 commits into
kernel-kind-termsfrom
kernel-all-fits

Conversation

@nicolas-abril

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

Copy link
Copy Markdown
Collaborator

Stacked on #1203 (base: kernel-kind-terms).

Why

bend2's LE goes under a binder. It compares a function type's domains swapped and its codomain along, so:

  • g : Type -> Nat fits Kind(&0) -> Nat;
  • K : Nat -> Kind(&2) fits Nat -> Type;
  • a rewrite of type Nat -> Kind(&0) fits a Nat -> Type goal.

The kernel fitted only at the top, so on #1203 safe.ts bridged the gap:

  • a self-call's argument went η-long where its domains or kinds differed from the column's (qsig_eq);
  • a rewrite went out at its own type (rwt_type).

--verdict trusted that bridge, and all three divergences that review found were in it. This moves the rule into the kernel, with proofs, so the kernel decides those fits itself.

Kernel (bend2/bendtt.lean)

  • Fits is inductive: conversion, kinds (*(g) fits *(h) where g is .Q2 wherever h is, as before), enums (fewer labels), ∀q A B fits ∀q C D when C fits A and B fits D, and transitivity. Transitivity is a rule, so the old nine-way fits_trans is gone.
  • Fits.at / fits_at read a fit at a former, in both directions. If T converts to a former X, then U converts to a Y that fits X part by part, and the same from U's side. fits_all, fits_conv, fits2 and fits_former follow from it. They replace the case analysis of the old disjunction, including fits_conv's "any non-kind fit converts", which a ∀ rule breaks.
  • Term.fits threads fuel, as qge does, and fits two ∀s of one quantity by their parts. fits_sound proves it.
  • Subject reduction and progress take the rule:
    • β casts the argument along the domain fit and the result along the codomain's;
    • a split, a hit and a miss do the same;
    • a λ-match on an enum may now receive a smaller enum;
    • lab_in reads a label through a fit.
  • Every claim (consistent, book_check, confluent, sr, progress, halts, empty) checks with no sorry under Lean v4.34.0 (the pinned version) and v4.34.1. Each depends only on [propext, Classical.choice, Quot.sound]. The claim statements are unchanged; the typing judgment they quantify over is now more general.
  • 63,988 ttok, against the cap of 64,000. The next kernel change has to simplify first.

Elaborator (bend2/safe.ts)

  • qsig_eq compares binder quantities only, since the kernel's fit still needs them equal.
  • rwt_type and the annotation it added are gone.

Checks

Paper

bend2/docs/BendTT/main.typ and paper/BendTT.pdf give the ∀ rule:

  • in the kinds section, with Bend examples;
  • in Figure 3's caption for U <= T, together with transitivity;
  • in the subject-reduction sketch, where a fit is inverted at a type former, so β casts along the domains' and codomains' fits.

The Lean line count is now 4,157.

🤖 Generated with Claude Code

nicolas-abril and others added 2 commits October 5, 2026 14:13
…d, the codomain along, so the kernel, not safe.ts, fits Nat -> Kind(&2) to Nat -> Type

bend2's LE compares a function type's domains swapped and its codomain
along, so g : Type -> Nat fits Kind(&0) -> Nat and K : Nat -> Kind(&2)
fits Nat -> Type. The kernel fitted only at the top, so safe.ts made up
for it: a self-call's argument went eta-long where the domains or kinds
differed (qsig_eq), and a rewrite went out at its own type (rwt_type).
--verdict trusted that bridge. Now the kernel has the rule, and proves it.

- Fits is inductive: conversion, kinds, enums, ∀s by their parts (the
  domain reversed), and a transitivity rule, so fits_trans is the rule.
  Fits.at and fits_at read a fit at a former, both ways, and give
  fits_all, fits_conv, fits2 and fits_former, which replace the case
  analysis of the old disjunction.
- Term.fits threads fuel and fits two ∀s of one quantity by their parts;
  fits_sound proves it.
- Subject reduction and progress take the ∀ rule: β casts the argument
  along the domain fit and the result along the codomain's; a split, a
  hit and a miss likewise; lab_in reads a label through a fit.
- Every claim (consistent, book_check, confluent, sr, progress, halts,
  empty) checks with no sorry and depends only on [propext,
  Classical.choice, Quot.sound], with Lean v4.34.0. 63,988 ttok (cap
  64,000).
- safe.ts: qsig_eq compares binder quantities only, and rwt_type is gone.

Hand-written books: the kernel rejects K : <A> -> *1 at <A> -> *2, a
∀(∀ *1 -> <A>) -> <A> at ∀(∀ *2 -> <A>) -> <A>, a function on <A> at
<A, B>, and a ∀ at a ∀+; it accepts each fit in the other direction.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… parts, the domain reversed, and subject reduction reads a fit at a former

- Kinds: function types fit by their parts, as in Bend, so a
  Nat -> Data fits where a Nat -> Type is expected, and a Type -> Nat
  where a Data -> Nat is.
- Figure 3's caption: U <= T adds the ∀ case and transitivity.
- Subject reduction: a fit is inverted at a type former like a
  conversion, so β casts the argument along the domains' fit and the
  result along the codomains'.
- bendtt.lean is 4,157 lines. paper/BendTT.pdf rebuilt with typst
  0.15.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nicolas-abril
nicolas-abril merged commit daa9295 into kernel-kind-terms Oct 5, 2026
1 check passed
@nicolas-abril

Copy link
Copy Markdown
Collaborator Author

Folded into #1203: kernel-kind-terms was fast-forwarded to this branch, so its commits (a8b85f0, daa9295) are part of #1203, and #1203's description covers the ∀ rule.

@nicolas-abril
nicolas-abril deleted the kernel-all-fits branch October 5, 2026 12:17
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.

1 participant