Skip to content

refactor(book): restructure chapters, extract Proof.lean, and fix the generated project - #23

Merged
arademaker merged 14 commits into
mainfrom
restructure/logic-and-chapter-order
Sep 14, 2026
Merged

arademaker merged 14 commits into
mainfrom
restructure/logic-and-chapter-order

Conversation

@arademaker

Copy link
Copy Markdown
Member

The restructuring agreed in September 2026, and the defects it uncovered.
Closes #3 and its five children (#8, #9, #10, #11, #12) — already closed with
their evidence — and #22.

The book's spine

The chapter order is now IntroCS, IntroL, Logic, Sets, SeaBattle,
Morphology, InfEngine, English. Mastermind is dropped (it announced a
semantics in propositional logic it never delivered), SeaBattle is promoted
to a chapter, and Games is gone.

Prop and the tactics were presented in three places. They are now presented
once, in a new CSwL/Logic/Proof.lean, which absorbs IntroL's "O tipo Prop e
Provas", PL's "Lógica Proposicional em Lean" and FOL's "As regras dos
quantificadores". Logic holds Proof, PL, FOL in that order; IntroL is
now about Lean as a programming language, keeping only the example/theorem/
rfl kernel that Morphology needs before Logic.

FOL gained a computable Formula.eval and the bridge into Prop that PL
already had, so the two chapters now have the same three-part shape: syntax as
data, computable semantics, and the theorem relating the two readings.

The generated project never compiled

Building the extracted project for the first time showed it had never worked.
This is the part worth reviewing closely, since the diagnosis in #22 turned out
to be wrong on both counts and the emitter was never at fault:

  • gapShip sat in the same ```lean +error fence as the definition meant to
    fail, so in the extracted project it was scoped inside an
    sf_expect_failure block while three examples used it at file scope.
  • Three solution! uses were written in a shape that only survives while the
    marker is there — a structure instance aligned against a column the marker
    created, and tactic blocks parenthesised rather than indented. As a tactic
    solution! is replaced by all_goals, so the block must suit a single goal;
    vestidos₁ had its rcases outside the marker and its bullets inside.
  • An import was dropped in silence because file := "introL" no longer matched
    import CSwL.IntroL, surfacing three chapters away as
    Unknown identifier IntroL.initS.

make now builds the generated solutions project (verify := true for that
variant alone), so a book that compiles while the student's project does not
fails loudly. The two reasons recorded for keeping that check off were stale
and are replaced with measurements: the toolchains now match, and Mathlib is
not rebuilt on every make — it is 7.5 GB vendored once, ~3 s incrementally.

Output that mirrors the source

Each section of Logic gets its own HTML page, and — following the principle
that the Lean output should mirror the source's file organisation — its own
generated module:

_out/<variant>/lean/CSwL/Logic.lean          glue
_out/<variant>/lean/CSwL/Logic/{Proof,PL,FOL}.lean

replacing one 1819-line file. The criterion is file :=, so a chapter whose
sections do not set it is untouched (Morphology is opt-in later). Each
section keeps the imports its own header declares. The silent import-dropping
path is now an error naming the file and the cause.

Checks

  • make all clean; the generated solutions and grading projects build with
    zero errors.
  • The split Lean was diffed against the previous single file: identical except
    that each section's headings rise one level, as a file's own headings should.
  • The STYLE-CODE.md ledger was rescanned rather than patched; five rows were
    wrong. native_decide is first met in Logic/PL, two chapters before the
    ledger claimed, and is still presented nowhere — recorded in "Known gaps",
    which changes Lean features used without being presented #7's picture of the same defect.

Note for the reviewer

student and terse generated projects still fail to build, by design: their
answers are sorry. Only solutions is verified.

Three sorrys remain in the sources (Sets.lean:258, :272,
Proof.lean:158). All predate this branch and are deliberate exercise
placeholders, though Proof.lean:158 reads as a proved theorem that is not —
worth a separate decision.

AI-usage disclosure: the work in this branch was carried out with the
assistance of Claude Opus 5 (Anthropic, September 2026, via Claude Code). The
author set the direction throughout — the chapter order, the decision that the
solution! failures were misuse rather than a macro defect, the principle that
the Lean output should mirror the source — and revised the prose. The assistant
diagnosed the extraction defects, wrote the saver changes, and ran the
verification. The author takes full responsibility for the final content.

The order becomes IntroCS, IntroL, Logic, Sets, SeaBattle, Morphology,
InfEngine, English. Two chapters move and one is created by promotion.

`SeaBattle` moves after `Logic` and `Sets` because its exercises prove
theorems about `WellFormed` by induction on an inductive predicate, which
needs tactics `Logic` presents. `Morphology` moves after `SeaBattle` so its
exercises may use those tactics too, instead of being confined to what
`IntroL` alone allows; it depends on nothing but `IntroL`, so the move is
free.

Mastermind is dropped. It was disconnected from the Sea Battle material
before it, and it announced a semantics in propositional logic that it never
gave — the propositional content was about eighteen lines the implementation
never used. Reinstating it would mean writing that encoding, not translating
it. Two exercises go with it, `four-turn-game` and `chess-grammar`.

With Mastermind gone `Games.lean` wrapped a single section, so `SeaBattle`
becomes the chapter: `CSwL/Games/SeaBattle.lean` moves to
`CSwL/SeaBattle.lean` and the glue file is deleted. The `Games` tag goes with
it — `IntroL`'s `{ref "Games"}` becomes `{ref "SeaBattle"}`.

Prose that named positions rather than chapters is corrected, as
STYLE-WRITING.md requires after a move: `Morphology`'s opening no longer
says "o capítulo anterior", and a stale comment in `Logic.lean` claiming
English precedes it is fixed.

Documentation that indexes by chapter order is updated: DEVIATIONS.md's
table, dependency paragraph and per-chapter sections (reordered and
renumbered); PROVENANCE.md's paths and dropped-exercise records;
README.md's chapter list; and STYLE-CODE.md's first-use ledger.

Re-deriving that ledger turned up something the original sweep missed:
`native_decide` is used eleven times in `SeaBattle.lean`, in ordinary code
rather than in solutions, so students see it. It is presented nowhere. The
known-gaps entry is widened accordingly; the fix belongs to #7.

Refs #3, #12.
Issues #9 and #12. The proof material was scattered: `IntroL` presented
`Prop`, the tactic table and induction; `PL` and `FOL` each re-presented
`Prop` before getting to their own subject. Four blocks now move verbatim
into a new `CSwL/Logic/Proof.lean`, which `Logic.lean` includes first:

  IntroL:300-623  "O tipo Prop e Provas"
  IntroL:724-748  "Prova por indução"
  PL:91-368       "Lógica Proposicional em Lean"
  FOL:44-126      "As regras dos quantificadores em Lean"

`IntroL` is now deliberately pre-proof: it uses `example`, `theorem` and
`rfl` only as the shape an exercise's tests take, and new prose says so
and forwards to `Proof` for what proving means. `PL` and `FOL` keep
syntax as a data type, computable semantics, and the bridge to `Prop`.

`PL`'s `variable (p q : Prop)` was leaking past the "Sintaxe" section and
shadowing the `valuation-table` exercise's own `p`, `q`, `r`; it is now
scoped. This only surfaced in the variant builds, not in `lake build`.

`STYLE-CODE.md`'s ledger is re-derived: the `Logic` row becomes three,
every proof tactic moves from `IntroL` to `Logic/Proof`, and `show`,
`omega` and `decide` are recorded under "Known gaps" — they survive only
inside the `twice` exercise's solutions, where nothing presents them.

A `:::dev` note in `Sets.lean` records that `Sets.Entity` and `FOL.Entity`
are distinct types sharing a name, accepted deliberately.

This commit was prepared with Claude Code. The AI performed the verbatim
block moves, re-derived the feature ledger, and drafted the new Portuguese
prose in `IntroL.lean` and `Logic/Proof.lean`; that prose is a draft
awaiting human review.
A reading pass over the chapter that the two preceding commits rearranged,
checking the text against what the code now does rather than against what it
did before the restructuring.

FOL gains a computable `Formula.eval` and the bridge section that PL already
had, so the chapter now has the same three-part shape as PL: syntax as data,
computable semantics, and the theorem relating the two readings. PL's
semantics section was rewritten around that same shape, and Proof was
condensed.

Fix five cross-references that resolved to nothing.

Record in `PROVENANCE.md` that CSwFP/5.19 and 5.20 became portable only with
this reorganization, since they need a semantics to be stated against, and
update the `STYLE-CODE.md` ledger for the features that moved with the text:
`List.all`/`List.any` to `IntroL`, `deriving BEq` from `Morphology` to `FOL`,
and `List.contains` and `induction … generalizing` newly used in `FOL`.

Add Nederpelt & Geuvers (2014) to the bibliography, cited where `Proof.lean`
explains that Lean's foundation makes types and programs computable.
The two-level table of contents was self-imposed. `htmlSplit := .never` means
"do not split here nor in any part below", so a glue chapter carrying it keeps
its sections on one page however long they grow. Dropping it from `Logic.lean`
lets Verso split at the depth it already defaults to (`htmlDepth := 2`), which
is what fp-lean runs.

Each section declares `file := "Tag"`, without which Verso builds the URL by
sluggifying the Portuguese title and the accents come out mangled
(`L___gica-proposicional`).

    _out/<variant>/html/Logic/{index,Proof,PL,FOL}/

The chapter index is now a 63 KB landing page instead of carrying all three
sections, and the four variants render with no unresolved cross-references.

The generated Lean is untouched, verified byte-identical against a snapshot
taken before the change: `walkOuter` writes one file per chapter and reads
`file :=` only from chapters, while `walkSection` takes its target file as a
parameter and never consults metadata. Splitting that output by section is the
other half of the issue and is left for its own commit, since it has to invert
`chapterImports`, which currently flattens a section's imports into its
chapter on purpose.

Refs #11

AI-usage disclosure: this change was developed with the assistance of Claude
Opus 5 (Anthropic, September 2026, via Claude Code). The author decided to
take up the issue and reviewed the result; the assistant made the edits,
checked the claims the issue made against Verso's source and the extractor's,
and verified the generated Lean was unchanged. The author takes full
responsibility for the final content.
`file := "introL"` renamed the generated chapter to `CSwL/introL.lean`, and
`import CSwL.IntroL` then stopped reaching the extracted project: the
generated `Morphology.lean` lost it and failed with `Unknown identifier
IntroL.initS`, plus every test downstream of `swedishPlural`.

`chapterModules` is built from the *generated* file names, so it held
`CSwL.introL` while the source header says `CSwL.IntroL`. The two no longer
matched, `isSection` (`CSwLMeta/Save/Project.lean`) concluded the import named
a section whose content had been merged into its chapter, and dropped it —
the one disposal path that does not reach the `reportError` for an
unresolvable import a few lines below. A `file :=` that does not match the
module name therefore removes an import in silence.

Introduced in 57a6702, found while building the generated project for #22.

Refs #22

AI-usage disclosure: this change was developed with the assistance of Claude
Opus 5 (Anthropic, September 2026, via Claude Code). The assistant traced the
missing import to the case mismatch and confirmed it by regenerating with the
name restored; the author reviewed the result. The author takes full
responsibility for the final content.
`gapShip` is a well-formed definition that happened to share a ```lean +error
fence with `badState`, the definition the fence is there to reject. In the
book both elaborate in place and nothing is wrong. In the extracted project
the fence becomes an indented `sf_expect_failure` block, so `gapShip` was
defined *inside* it and the three examples below, at file scope, could not see
it — reported as `Expected type must not contain free variables` from the
`native_decide` that needed it.

It now has a fence of its own, immediately before, and the `+error` fence
holds only what is meant to fail.

The issue attributed this to `solution!(by …)` emitting `(by …)`. That is not
the cause: removing the parentheses by hand leaves the error exactly where it
was, and the parenthesised form elaborates fine.

Refs #22

AI-usage disclosure: this change was developed with the assistance of Claude
Opus 5 (Anthropic, September 2026, via Claude Code). The assistant tested the
parenthesis hypothesis the issue proposed, found it did not hold, and located
the scoping cause; the author reviewed the result. The author takes full
responsibility for the final content.
Three solutions were written in a shape that only survives while the marker
is there. The `solutions` variant strips the marker in place, and what was
left did not parse or did not prove.

`Sets.lean`, `ex_3_12`: a structure instance opened on the same line as
`solution!(`, and its remaining fields were aligned against a column that the
marker created. Removing `solution!` shortens the first line by nine
characters, the fields no longer line up under `refl`, and the instance fails
to parse. The body now starts on the line below, indented, so the alignment
is its own.

`Proof.lean`, three tactic blocks: written `solution!( … )` rather than as an
indented block. As a tactic the marker is replaced by `all_goals`, so the
block has to be applicable to a single goal. Two were merely parenthesised and
became indented. In `vestidos₁` the shape was wrong: `rcases` ran outside the
marker and the three bullets inside it, so `all_goals` applied all three to
each of the three goals it left open. The `rcases` moves inside, and the block
opens and closes the case split itself.

`STYLE-CODE.md` now states both rules, which it did not: a tactic solution
takes the indented form and must suit a single goal, and a multi-line term
begins on the line after `solution!(`.

The emitter is not at fault and is unchanged: `solution!` is used in both
forms in sf-in-lean, and a parenthesised *term* — including a `by` block — is
what it is for.

Refs #22

AI-usage disclosure: this change was developed with the assistance of Claude
Opus 5 (Anthropic, September 2026, via Claude Code). The author judged the
fault to lie in the book's use of `solution!` rather than in the macro and
pointed at sf-in-lean for the idiom; the assistant located the three
occurrences, found the `all_goals` constraint behind the `vestidos₁` failure,
and wrote the style-guide entry. The author takes full responsibility for the
final content.
`buildProject` has been there since the saver was written, behind a `verify`
flag that defaulted to `false` and that nothing ever set. The three defects
fixed in this branch all had the same shape — the book compiled, the project
handed to the student did not — and none of them was visible to `lake build`
at the repository root, where a solution is elaborated in place, marker and
all. Only the extracted source shows what the student receives.

`verify := true` for `solutions` alone. It is the one variant whose proofs are
all meant to be complete, so "it compiles" both means something and is now
true. `student` and `terse` replace answers with `sorry` and fail by design;
verifying them would report expected failures as errors. `grading` is the same
Lean with the autograder's attributes over it.

The two reasons recorded for keeping this off no longer hold, and the comment
now says what was measured instead of what was assumed. The toolchain
mismatch is gone: the generated project and `CSwL` are both on `v4.33.0`. And
Mathlib is not compiled "from scratch on every `make`" — the generated project
vendors its own, 7.5 GB, but once built an incremental `lake build` takes
about three seconds. The cost that remains is disk, and a `make clean` that
pays for it again.

Checked by reintroducing the `ex_3_12` defect: `make solutions` fails, exit 2,
naming the file and line inside the generated project.

Closes #22

AI-usage disclosure: this change was developed with the assistance of Claude
Opus 5 (Anthropic, September 2026, via Claude Code). The author decided to
turn the check on; the assistant measured the two recorded objections, found
both stale, limited the flag to `solutions`, and verified that a failing
generated project fails `make`. The author takes full responsibility for the
final content.
The extracted project mirrored the book's chapters but not its files: three
section files of 441, 599 and 772 lines arrived merged into one 1819-line
`CSwL/Logic.lean`, while their sources sit in `CSwL/Logic/`. The output now
mirrors the source — a `PL.lean` in the book is a `PL.lean` in the project —
and the chapter becomes a glue module importing its sections.

The criterion is `file :=`. It cannot be read off the document: after
`{include 1 …}` a section that came from its own file and one written inline
in the chapter are the same `Part`. The key is already what names the HTML
page, and only the three sections that should become files carry it, so
`isOwnModule` asks for it and the inline sections (`pl-syntax`,
`pl-semantics`, …) stay merged as before. Nothing changes for a chapter whose
sections set no `file :=` — `Morphology` is untouched until someone adds the
key.

`chapterImports` did not need inverting, only documenting: it keys on
`chapterModules`, which is built from the generated file names, so a section
that now has a module of its own is no longer taken for a merged one and its
`import` survives as written. Each section keeps the imports its own header
declares — `Mathlib.Tactic.ByContra` lands in `PL.lean`, `Mathlib.Tactic.Use`
in `FOL.lean` — which is what 0b137cb had to work around while the output was
flat.

The silent drop that 0b137cb worked around and that 47e435a ran into is now
an error. An `import` that resolves to a chapter the project emits under
another name — `CSwL.IntroL` against a chapter emitted as `introL.lean` — used
to be taken for a merged section and dissolved, and the failure surfaced three
chapters away as `Unknown identifier IntroL.initS`. Extraction now stops and
names the file and the cause.

Verified: the split content is identical to the previous single file except
that each section's headings rise one level, as a file's own headings should;
all four variants emit the same eleven modules; and the generated `solutions`
project still builds, which is the check #22 turned on.

Refs #11

AI-usage disclosure: this change was developed with the assistance of Claude
Opus 5 (Anthropic, September 2026, via Claude Code). The author set the
principle that the Lean output should mirror the source's file organisation;
the assistant chose `file :=` as the criterion, wrote the change, and verified
the split against the previous output. The author takes full responsibility
for the final content.
…se it

`CSwLCompat` backs the `sf_experiment` and `sf_expect_failure` macros that a
```lean +error fence becomes in the extracted project. Only `SeaBattle.lean`
and `Logic/PL.lean` have such a fence; `Logic.lean` and `Logic/Proof.lean`
imported the module without using it, and the extracted project carried the
import into the student's files.

The module itself is still needed, in every variant including `student`: the
two fences that remain are pedagogical — `badState`, which must fail to
typecheck, and `doesNotWork`, which shows that a proof of a `Prop` cannot be
pattern-matched — so the blocks belong in the student's project and the
project does not build without the macro that carries them.

AI-usage disclosure: this change was developed with the assistance of Claude
Opus 5 (Anthropic, September 2026, via Claude Code). The author asked whether
the module was needed in the student output; the assistant established that it
is, found the two imports that are not, and removed them. The author takes
full responsibility for the final content.
…order

The ledger is indexed by book order, and the reorganisation moved nearly every
row. It had been patched by hand as chapters moved; rescanning the sources
found five rows that no longer said where a feature is first used.

- `native_decide` — `Logic/PL`, not `SeaBattle`. It is named in the prose of
  three exercises there (`:282`, `:308`, `:348`), two chapters before the row
  claimed. This is the worst of the five: the tactic trusts the compiler
  rather than the kernel, and "Known gaps" now records that `Logic/PL` is
  where the explanation it still lacks belongs.
- `assumption` — `Logic/Proof`, not `Sets`. It is presented there in prose
  (`:172`) and used at `:182`, so this row was not a gap, only misplaced.
- `DecidableEq` — `IntroL`, not `Logic/PL`. Presented twice, at `:327` with
  `deriving` and at `:862` alongside `BEq`.
- `trivial` — stays in `Sets`, but it is a term there (`:517`), not a tactic,
  and moves to the types column.
- `funext` — solution only, like the `show`/`omega`/`decide` beside it: its
  only use is inside the `twice` exercise's answer.

Stale line numbers in "Known gaps" corrected (`Sets.lean:507` → `:517`, the
`twice` exercise's `:1154-1158` → `:1136-1141`).

"How to read the table" gains the scanning method, since the naive one is what
let these drift: a search that ignores ```` ```lean ```` fences reports
Portuguese as Lean — "trivialmente" matches `trivial` — and a tactic named in
a sentence is a mention, not a use. Uses are found inside fences with comments
stripped, presentations in the prose, and the rule holds only when a
presentation precedes the first use in book order.

Closes #10

AI-usage disclosure: this change was developed with the assistance of Claude
Opus 5 (Anthropic, September 2026, via Claude Code). The assistant wrote the
fence-aware scan, checked each disagreement between it and the table against
the sources, and distinguished the real errors from matches on Portuguese
prose; the author reviewed the result. The author takes full responsibility
for the final content.
Copilot AI lite review requested due to automatic review settings September 14, 2026 04:17

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved critical build, extraction, and semantic issues remain, along with moderate correctness issues.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

This PR restructures the book, consolidates proof material under Logic, adds computable FOL semantics, and improves generated-project extraction.

Changes:

  • Reorders chapters, promotes SeaBattle, removes Games/Mastermind, and narrows IntroL.
  • Adds Logic/Proof.lean and splits generated Logic modules.
  • Updates extraction validation, documentation, and project verification.
File summaries
File Summary and final comments
STYLE-CODE.md Updates the feature ledger and extraction guidance. Three nits: inaccurate Proof description (2 votes), omitted linarith (1), and omitted Proof from the split example (1).
README.md Updates project organization. One nit (1): document Logic/Proof.lean.
PROVENANCE.md Updates provenance inventory. One nit (3): regenerate the incorrect count and stale identifiers/paths.
DEVIATIONS.md Documents restructuring. Four nits (2, 3, 1, 1): stale SeaBattle, IntroL, Morphology, and migration descriptions.
CSwLMeta/Save/Project.lean Adds generated-project validation and import checks; no final comments.
CSwLMeta/Save/Extract.lean Adds section-level generated modules; no final comments.
CSwL/Sets.lean Updates exercise extraction; no final comments.
CSwL/SeaBattle.lean Promotes SeaBattle and adjusts extraction scope. One critical comment (1): exposed examples still use incompatible term-form solution markers.
CSwL/Morphology.lean Updates chapter integration; no final comments.
CSwL/Logic/Proof.lean Consolidates proof material. Two critical comments (1 each), one moderate (3), and four nits (2, 1, 1, 1): solution-marker extraction failures, an unproved theorem, spelling errors, and an untracked linarith example.
CSwL/Logic/PL.lean Refactors propositional semantics. Three critical comments (3, 3, 1), two moderate (3, 2), and four nits (1 each): invalid Boolean operators/types, valuation pairing, insufficient testing, and solution-marker formatting.
CSwL/Logic/FOL.lean Adds computable FOL semantics. One nit (1): align the model introduction with the predicates actually used.
CSwL/Logic.lean Provides Logic glue; no final comments.
CSwL/IntroL.lean Narrows IntroL to programming-language material; no final comments.
CSwL/Games/Mastermind.lean Removes Mastermind material; no final comments.
CSwL/Games.lean Removes obsolete Games glue; no final comments.
Book.lean Applies the revised chapter order; no final comments.
Bib.lean Adds supporting references; no final comments.
Review details

Suppressed comments (17)

CSwL/Logic/FOL.lean:396

  • The model introduced below is not limited to P, R, and S: int0 interprets eight named predicates (Girl, Boy, Princess, Dwarf, Giant, Child, Love, and Defeat). As written, the semantic setup describes a different language from the one the examples evaluate; align this introduction with the concrete model.
Por conveniência, nos limitamos a um fragmento de língua com apenas três letras de predicado: `P` (unário), `R` (binário), e `S` (ternário).

Como deve ser uma estrutura extralinguística para as constantes `P`, `R` e `S`? Tal estrutura deve conter ao menos um domínio de discurso `D`, formado por entidades individuais, com uma interpretação para `P`, para `R` e para `S`. Essas interpretações são dadas por uma função `Interp`, que a cada nome de predicado e a cada lista de elementos do domínio associa um valor de verdade.

CSwL/Logic/PL.lean:354

  • This proof uses the parenthesized by solution!(native_decide) shape instead of the standalone indented tactic form required by STYLE-CODE.md:184-188. Use an indented solution! block so the source follows the extraction contract consistently.
example : Form.impliesL [depo1, depo2, depo3] banguSolution = true :=
  by solution!(native_decide)

CSwL/Logic/PL.lean:247

  • These proofs use the parenthesized by solution!(decide) shape instead of the standalone indented tactic form required by STYLE-CODE.md:184-188. Use an indented solution! block so the source follows the extraction contract consistently.
example : form3.eval vs1 = true := by solution!(decide)
example : form4.eval vs1 = true := by solution!(decide)
example : form5.eval vs2 = true := by solution!(decide)

CSwL/Logic/PL.lean:289

  • This marker is also used in the parenthesized form inside a tactic proof. STYLE-CODE.md:184-188 requires tactic answers to use standalone indentation; change the marker to an indented block rather than relying on the term-shaped form.
  solution!(native_decide)

CSwL/Logic/PL.lean:318

  • This native_decide proof uses solution!(…) as a tactic block, but the repository's extraction convention requires the standalone indented tactic form. Put the marker on its own line and indent native_decide beneath it.
  solution!(native_decide)

CSwL/Logic/Proof.lean:171

  • Correct the spelling of tatica to tática.
A regra de introdução de `→` diz que para provar `P → Q`, supomos `P` e derivamos `Q`. A tatica `intro` move o antecedente para as hipóteses. A regra de eliminação é a chamada regra *modus ponens*. De `P → Q` e de `P`, conclua `Q`. Em Lean isso é aplicação `h hP` já é a prova de `Q`. A tática `apply` faz o mesmo de trás para frente, ela transforma o objetivo `Q` no objetivo `P`. A {tactic}`exact` fecha a prova indicando a hipótese cujo tipo corresponde ao _goal_ aberto. A {tactic}`assumption` fecha o _goal_ quando o tipo de alguma das hipóteses corresponde ao tipo do _goal_, sem precisarmos passar a hipótese nominalmente, como quando usamos {tactic}`exact`.

CSwL/Logic/Proof.lean:57

  • Correct the spelling of identificas to idênticas.
A tática {tactic}`rfl` tem limitações, embora possamos provar que duas funções são identificas a menos da sua mudança nos nomes dos parâmetros, precisamos do teorema sobre a comutatividade dos naturais para provar o segundo exemplo.

CSwL/Logic/Proof.lean:354

  • This tactic solution is still written as solution!(…); after marker stripping it is not the required standalone indented tactic block, so the generated solutions source can fail even though the book source elaborates with the marker. Use the standalone tactic form.
  solution!(
    intro hp
    apply h2
    apply h
    exact hp)

CSwL/Logic/Proof.lean:532

  • This newly added non-solution example uses linarith, but the Logic/Proof row in STYLE-CODE.md does not record it and the recap below lists other tactics instead. Either record its presentation/first use in the ledger or replace this example with a tactic already accounted for, so the feature ledger remains accurate.
    linarith

CSwL/Logic/Proof.lean:368

  • This is another tactic solution written as solution!(…) after by, contrary to the standalone indented form required by the saver. In the extracted solutions it does not have the intended all_goals block shape; move solution! to its own line and indent all tactics beneath it.
  solution!(
    intro h
    unfold E at h
    linarith)

CSwL/Logic/Proof.lean:381

  • This proof has the same parenthesized tactic-marker shape. Keep the entire tactic sequence inside one standalone indented solution! block so the generated solution replaces the marker with all_goals without changing the block's structure.
  solution!(
    intro h
    unfold E at h
    obtain ⟨h1, h2⟩ := h
    rewrite [h1,h2]

CSwL/SeaBattle.lean:302

  • Closing the +error block here exposes the following exercise examples to the extracted solutions project, but those examples still use term-form solution!(by native_decide). The teacher rewrite removes only solution!, producing parenthesized tactic terms such as (by native_decide), which is the generated-project failure reported for addShip; rewrite these examples using the indented tactic form (or fix the term-marker emitter) before enabling verification.
    DEVIATIONS.md:92
  • The dependency rationale says all Morphology proofs are rfl, but CSwL/Morphology/SwedishPlural.lean:69 and :72 still use native_decide. This makes the chapter-order documentation false and hides the same known ledger gap this PR records; qualify the statement with those two exceptions.
`Morphology.lean` requires only `IntroL.lean` — its three sections are programs, and the proofs in them are `rfl` on concrete values. It is placed after `SeaBattle.lean` rather than at its old position right after `IntroL.lean` so that its exercises may use the tactics `Logic.lean` presents, rather than being confined to what `IntroL.lean` alone allows.

DEVIATIONS.md:335

  • This migration note is stale after moving Morphology after Logic: it says every feature must have been presented in IntroL, while the surrounding rationale explicitly allows the chapter to use tactics from Logic and the sources include later/solution-only features. Point the check at the actual ledger/order instead.
*Migration*: check that every Lean feature used here was presented in `IntroL.lean`.

README.md:72

  • The file-organization example omits the newly extracted CSwL/Logic/Proof.lean, even though Proof is the first included section and has its own generated module. Include it so the README describes all three Logic section files.
(`CSwL/Logic/PL.lean`, `CSwL/Logic/FOL.lean`) — the same pattern

STYLE-CODE.md:62

  • The regenerated ledger omits linarith, although the new Proof.lean presents and uses it (Proof.lean:359-368 and :532). Add it to this first-use row; otherwise the ledger is incomplete and the feature is not tracked.
| `Logic/Proof` | `open` | `¬`, `∀`, `∃`, `∧`, `∨`, `↔`, `≠` | `intro`, `exact`, `apply`, `cases … with`, `constructor`, `obtain`, `have`, `use`, `left`, `right`, `rcases`, `by_cases`, `by_contra`, `assumption` |

STYLE-CODE.md:149

  • The HTML-splitting example lists only Logic/PL/ and Logic/FOL/, but the new Proof section also has file := "Proof" and becomes Logic/Proof/. The style guidance should not omit the first section it is intended to describe.
the chapter's directory — `Logic/PL/`, `Logic/FOL/` — which is what the
  • Files reviewed: 18/18 changed files
  • Comments generated: 13
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread CSwL/Logic/PL.lean Outdated
Comment thread CSwL/Logic/PL.lean Outdated
Comment thread CSwL/Logic/PL.lean Outdated
Comment on lines +317 to +318
example : Feq1.equivalent Feq2 := by
solution!(native_decide)
Comment thread CSwL/Logic/Proof.lean Outdated
Comment on lines +331 to +341
solution!(
constructor
· intro h
obtain ⟨h1, h2⟩ := h
apply And.intro
· exact h2
· exact h1
· intro h
constructor
· exact h.2
· exact h.1)
Comment thread CSwL/Logic/Proof.lean Outdated
Comment on lines +420 to +427
have hMa : Ma := by
rcases ha with hMa | hAa | hCa
· solution!
exact hMa
· solution!
exact absurd hAa hnAa
· solution!
exact absurd hCa hnCa
Comment thread CSwL/Logic/Proof.lean Outdated
Comment thread DEVIATIONS.md
### Grammars: Mathlib's `ContextFreeGrammar`, deferred

`Games.lean` presents a BNF grammar for each game in prose, and then models it not as a grammar but as a handful of ordinary Lean types: enumerations for the terminal categories (`Colour`, `Answer`, `Column`, `Ship`), a `structure` for each rule with a fixed shape (`Turn`, `Attack`, `Move`), and `List`, `Vector` or a subtype where the BNF recurses or bounds a length (`abbrev Game := List Turn`, `abbrev Guess := Vector Colour 4`, `Reaction := { r : List Answer // r.length ≤ 4 }`).
`SeaBattle.lean` presents a BNF grammar in prose, and then models it not as a grammar but as a handful of ordinary Lean types: enumerations for the terminal categories (`Colour`, `Answer`, `Column`, `Ship`), a `structure` for each rule with a fixed shape (`Turn`, `Attack`, `Move`), and `List`, `Vector` or a subtype where the BNF recurses or bounds a length (`abbrev Game := List Turn`, `abbrev Guess := Vector Colour 4`, `Reaction := { r : List Answer // r.length ≤ 4 }`).
Comment thread DEVIATIONS.md Outdated
**`instance` is presented here.** The chapter's "Classes de tipos" section shows type classes only from the *use* side — the `[BEq α]` in a signature, and the difference between `BEq` and `DecidableEq`. But instances are declared from `Logic.lean` onwards: `PL.lean` gives `ToString Form`, `FOL.lean` three more, and `English.lean` fifteen, all of them `ToString`. Declaring an instance is a small step from the section already there, and it is the last piece of type classes the book actually needs — no chapter declares a `class` of its own.

**`Prop` is presented here, minimally.** Not by choice: inductive types bring `deriving DecidableEq`, `decide` and `#check 1 = 1`, all of which display `Prop`. `Games/Mastermind.lean` already derives `DecidableEq` on `Colour` and `Answer` in its first code block, two chapters before any logic. The student sees `Prop` whether or not it is introduced. So the chapter presents proposition-as-type, proof-as-term, and `rfl`, `intro`, `exact`, `decide` — and leaves natural deduction and quantifiers to `Logic.lean`. Without this, `IntroL.lean`, `Morphology.lean` and `Games.lean` are `Bool` and `#eval` throughout, which is the original book with Lean as a costume.
**`Prop` is presented here, minimally.** Not by choice: inductive types bring `deriving DecidableEq`, `decide` and `#check 1 = 1`, all of which display `Prop`. `SeaBattle.lean` already derives `DecidableEq` on its enumerations and `Answer` in its first code block, two chapters before any logic. The student sees `Prop` whether or not it is introduced. So the chapter presents proposition-as-type, proof-as-term, and `rfl`, `intro`, `exact`, `decide` — and leaves natural deduction and quantifiers to `Logic.lean`. Without this, `IntroL.lean`, `Morphology.lean` and `SeaBattle.lean` are `Bool` and `#eval` throughout, which is the original book with Lean as a costume.
Comment thread PROVENANCE.md
Comment on lines +23 to 27
The book has 76 exercises as of 2026-09-13, and all but one of them
appear somewhere below — either in a table that names its source, or
in the list of those with no counterpart. Two checks keep it that way:
no `(name := …)` in `CSwL/` should be absent from this file, and no
name cited here should have stopped existing.
Comment thread STYLE-CODE.md
Comment on lines +38 to +40
column does not by itself settle whether the rule holds. `Logic/Proof.lean`
presents fourteen tactics in a plain code fence — one line each, `rfl` through
`funext` — and a scan that reads only ```` ```lean ```` blocks misses it. Check
`IntroL.lean` loses roughly 80% of its lines. Three sections leave it:
"As duas leituras de uma função" and "Tipos na gramática e na
computação" move on, and "Tipos como disciplina" is dropped as the
book's thesis rather than the chapter's content. The `leanOutput`
blocks and `#reduce` go with them. What remains is the language the
rest of the book uses, and the chapter is left deliberately pre-proof.

`Proof.lean` gains the extensional/intensional discussion as a new
section, "Extensionalidade de Funções", which is where `funext`
belongs now that it is presented as a tactic. Its sections gain tags,
"Prova por indução" becomes "Provas por Indução", and a new exercise
`implication-as-disj` is added while `and-comm` drops to one star.

`PL.lean` and `FOL.lean` get prose revisions. `FOL.lean` also renders
its quantifiers as `∀`/`∃` rather than `A`/`E`, and its
scope-ambiguity passage is cut. Cross-references that pointed at an
exercise now point at a section instead: exercises cannot be
`{ref}`-ed, tracked in #24.

`DEVIATIONS.md` catches up with all of this. CSwFP/2.5 — the type BNF
and the three typing rules — moves from `IntroL.lean` to
`English.lean`, which already carried the rest of 2.5 and already
names `e` and `t`. The paragraph claiming `Prop` is presented in
`IntroL.lean` is rewritten: the argument for it was that the student
would meet `Prop` unintroduced, and that fell when `Proof.lean` became
part of the third chapter, ahead of every chapter that displays it.
Two stale claims are corrected along the way — the `restful` example
is gone with 2.5, and the instances declared downstream are three
`Repr` in `FOL.lean`, not `ToString` in `PL.lean`.
@arademaker
arademaker merged commit 1e30bec into main Sep 14, 2026
1 check passed
@arademaker
arademaker deleted the restructure/logic-and-chapter-order branch September 14, 2026 20:42
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.

Restructuring: chapter order, Proof.lean, and what depends on what

2 participants