Skip to content

feat(control): cover the whole do fragment in every judgment, with loop rules - #188

Draft
dtumad wants to merge 1 commit into
kernel/upstream-wp-instancesfrom
kernel/structural-coverage
Draft

feat(control): cover the whole do fragment in every judgment, with loop rules#188
dtumad wants to merge 1 commit into
kernel/upstream-wp-instancesfrom
kernel/structural-coverage

Conversation

@dtumad

@dtumad dtumad commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

Stacked on #187. Gives each construct that core do-notation elaborates to a rule in each PolyFun judgment, so reasoning about ordinary monadic code never unfolds a judgment by hand.

  • Control/Monad/Support/Structural.leanCanReturn / AllOutputs / SomeOutput / NoOutput through <*, *>, if, if h :, Option.elim, Sum.elim, <$>, <*>. Tagging follows what grind can index: Option.elim / Sum.elim reachability is @[simp, grind =]; ite heads and thunked applicative operands cannot be patterns, so those stay @[simp] (recorded as a gotcha).
  • Control/Monad/Support/Loops.lean — invariant rules for forIn' / forIn / foldlM over lists and PureForIn containers, obtained from core's Spec.* lemmas under the demonic and angelic instances of feat(control): bridge the program-logic kernel to core's lattice-generic WP stack #187, plus forM by induction.
  • Algebra.lean, Hom.lean, Hom/Loops.lean, PFunctor/Free/WP.lean — the same constructs for MAlgOrdered.wp, MonadHom, and wpFold; morphisms commute with every loop combinator (@[simp, grind =]).
  • Control/Do/Spec.lean@[spec] Spec.forM_list for vcgen (tactic tier).
  • SplitSupport.lean → root + Support/Instances.lean + Support/Indexed.lean, no renames.

Canaries

PolyFunTest/Control/SupportStructural.lean (one-tactic gates), PolyFunTest/Control/MonadHomLoops.lean, and in PolyFunTest/Do/Support.lean a let mut accumulator over a for loop verified by vcgen … invariants · fun pref _ s => s = pref.sum through core's Spec.forIn_list, converted back to AllOutputs.

Left out (recorded in the landscape memo)

Relational (MAlgRelOrdered) loop rules, a mapM judgment rule, and try/catch through the lifted ExceptT instance over a PolyFun base — vcgen reports No spec found for program tryCatch … there although Spec.tryCatch_ExceptT exists at the pin; the instance path needs diagnosing.

Validation

./scripts/validate.sh --lint --test --axioms — lint passes for PolyFun and ToCslib; 11030 declarations, zero sorry/axiom taint.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Nb4g3Vxgjhnhsca7BzAsFc

…loop rules

Give each construct core `do`-notation elaborates to a rule in each of
PolyFun's judgments, so that reasoning about ordinary monadic code never has to
unfold a judgment by hand:

- `Control/Monad/Support/Structural.lean`: `CanReturn`, `AllOutputs`,
  `SomeOutput`, and `NoOutput` through `<*`, `*>`, `if`, `if h :`,
  `Option.elim`, `Sum.elim`, `<$>`, and `<*>`; the `Option.elim` / `Sum.elim`
  reachability equations are `@[simp, grind =]`, the rest `@[simp]`, since
  `grind` refuses `ite` heads and thunked applicative operands as patterns;
- `Control/Monad/Support/Loops.lean`: invariant rules for `forIn'` / `forIn` /
  `foldlM` over lists and `PureForIn` containers, obtained from core's
  `Spec.*` specifications under the demonic and angelic `WPMonad` instances,
  plus `forM` by induction — support reasoning about loops without a triple;
- `Control/Monad/Algebra.lean`: `wp_seqLeft`, `wp_seqRight`, `wp_ite`,
  `wp_dite`, `wp_option_elim`, `wp_sum_elim` join the inward-normalizing
  `@[simp]` set; `Control/Monad/Hom.lean` and `Hom/Loops.lean`: a monad
  morphism commutes with branching and with every loop combinator;
  `PFunctor/Free/WP.lean`: the same for `wpFold`;
- `Control/Do/Spec.lean`: `@[spec] Spec.forM_list`, the list loop core does
  not specify, in the tactic tier of the quarantine.

`Control/Monad/Support.lean` is split under the 1500-line cap: instances and
lift transport move to `Support/Instances.lean`, the per-run support of
`StateT` / `ReaderT` to `Support/Indexed.lean`; no declaration changes name.

Canaries: `PolyFunTest/Control/SupportStructural.lean` (one-tactic gates),
`PolyFunTest/Control/MonadHomLoops.lean`, and, in `PolyFunTest/Do/Support.lean`,
a `let mut` accumulator over a `for` loop verified by `vcgen` with a loop
invariant through core's `Spec.forIn_list`, converted back to the "always"
judgment. The program-logic page gains a coverage table; the landscape memo
records the follow-ups (relational loop rules, a `mapM` judgment rule, and
`try/catch` through the lifted `ExceptT` instance, where `vcgen` reports no
applicable spec).

Validated with `./scripts/validate.sh --lint --test --axioms` (zero
sorry/axiom taint).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nb4g3Vxgjhnhsca7BzAsFc
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