2026-07-03 07:44:40 +00:00
|
|
|
|
\chapter{Tactics: Proving as a Dialogue}
|
|
|
|
|
|
\label{ch:tactics}
|
|
|
|
|
|
|
|
|
|
|
|
\section{From programs to conversations}
|
|
|
|
|
|
|
book overhaul moves 3-5: hook transplants, suspense mechanics, voice unification
Per the 7-reader didactic panel and BOOK-OVERHAUL-PLAN.md:
- front matter: box legend demoted below a lived example (the aha box
becomes its own legend entry)
- ch04: open on the stake (proof the size of a compiler), new section
'When you get stuck --- and you will' promoting the debugging session,
checkpoint now carries the omega cliffhanger forward
- ch06: open on the dare (invert 19 mod a 77-digit prime, two-digit
numbers only), machine-referee #eval after the Euclid box, checkpoint
distills the constant-time trade into one quotable sentence
- ch10: cold-open on the 12 GB crash, spec vocabulary re-armed at the
summit statement, falsification tryit after the 16p box (the -151
#eval), wall dispatch tied to the cold open, closing paragraph places
the certificate in the live log
- ch12: opening pyramid figure now carries question marks resolved
layer by layer through the chapter (suspense instead of spoiler),
kernel-wall rendered as a scene, 'Where you come in' promoted to its
own subsection, false 'closing chapter' removed
- appendix-toolkit: opens in the design-review room, Drill 7b (parity
argument), street assignment close
- appendix-walkthroughs: opens at the reader's low point, one-hole-one-
paragraph contract, counts replaced by 'trust the folder'
- appendix-repo-tour: active three-promise opener, sabotage-the-button
tryit, final tour stop at the transparency log
Build verified: tectonic clean, 118 pages, zero unresolved refs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-07 22:38:44 +00:00
|
|
|
|
Here is the problem with everything you learned in the last chapter: a real
|
|
|
|
|
|
correctness proof for field multiplication --- the theorem this book is
|
|
|
|
|
|
climbing toward --- would, written as a raw proof program, be a program the
|
|
|
|
|
|
size of a small compiler. Nobody writes those by hand. (Chapter~\ref{ch:pat}'s
|
|
|
|
|
|
handcrafted terms were honest work; honest work does not scale.)
|
2026-07-03 07:44:40 +00:00
|
|
|
|
Instead, Lean offers \emph{tactic mode}: an interactive dialogue where you
|
|
|
|
|
|
issue commands and Lean builds the proof program for you, step by step,
|
|
|
|
|
|
showing you the remaining work after each move.
|
|
|
|
|
|
|
|
|
|
|
|
You enter the dialogue with the keyword \lean{by}:
|
|
|
|
|
|
|
|
|
|
|
|
\begin{lstlisting}[language=Lean]
|
|
|
|
|
|
theorem and_swap (P Q : Prop) : P ∧ Q → Q ∧ P := by
|
|
|
|
|
|
intro h
|
|
|
|
|
|
constructor
|
|
|
|
|
|
· exact h.2
|
|
|
|
|
|
· exact h.1
|
|
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
|
|
|
|
|
|
Place your cursor after \lean{by} in the editor and Lean shows the
|
|
|
|
|
|
\textbf{goal state} --- the exact logical situation at that point:
|
|
|
|
|
|
|
|
|
|
|
|
\begin{lstlisting}
|
|
|
|
|
|
P Q : Prop
|
|
|
|
|
|
⊢ P ∧ Q → Q ∧ P
|
|
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
|
|
|
|
|
|
Everything above the turnstile \(\vdash\) is what you \emph{have} (the
|
|
|
|
|
|
context); the line after it is what you \emph{owe} (the goal). Every tactic
|
|
|
|
|
|
transforms this picture. After \lean{intro h}, the hypothesis moves above the
|
|
|
|
|
|
line; after \lean{constructor}, the goal splits in two. Proving becomes a
|
|
|
|
|
|
game whose board you can always see.
|
|
|
|
|
|
|
|
|
|
|
|
\begin{bigidea}
|
|
|
|
|
|
A tactic proof is a \textbf{recorded conversation with the goal state}. The
|
|
|
|
|
|
skill of proving is not memorizing tactic names --- it is learning to
|
|
|
|
|
|
\emph{read the goal state} and recognize which of a handful of moves makes it
|
|
|
|
|
|
simpler. Below is the core vocabulary; it covers the vast majority of every
|
|
|
|
|
|
proof in the real Ed25519 development.
|
|
|
|
|
|
\end{bigidea}
|
|
|
|
|
|
|
|
|
|
|
|
\begin{center}
|
|
|
|
|
|
\begin{tabular}{@{}lll@{}}
|
|
|
|
|
|
\toprule
|
|
|
|
|
|
\textbf{Tactic} & \textbf{When the goal looks like...} & \textbf{Effect} \\
|
|
|
|
|
|
\midrule
|
|
|
|
|
|
\lean{intro h} & \lean{P → Q}, \ \lean{∀ x, P x} & assume it; name the evidence \\
|
|
|
|
|
|
\lean{exact e} & anything & finish: \lean{e} is a proof of the goal \\
|
|
|
|
|
|
\lean{apply f} & \lean{Q}, given \lean{f : P → Q} & reduce the goal to \lean{P} \\
|
|
|
|
|
|
\lean{constructor} & \lean{P ∧ Q}, \lean{P ↔ Q}, ... & split into pieces \\
|
|
|
|
|
|
\lean{cases h} & have \lean{h : P ∨ Q} (or \(\wedge\), \lean{∃}) & case analysis on \lean{h} \\
|
|
|
|
|
|
\lean{rw [eq]} & contains a rewritable subterm & replace using equation \lean{eq} \\
|
|
|
|
|
|
\lean{simp} & simplifiable clutter & rewrite with a lemma database \\
|
|
|
|
|
|
\lean{induction n} & \lean{∀ n : Nat, ...} & base case + inductive step \\
|
|
|
|
|
|
\lean{rfl} & \lean{a = a} after computation & close by computation \\
|
|
|
|
|
|
\bottomrule
|
|
|
|
|
|
\end{tabular}
|
|
|
|
|
|
\end{center}
|
|
|
|
|
|
|
|
|
|
|
|
\section{Rewriting: equality as a tool}
|
|
|
|
|
|
|
|
|
|
|
|
The workhorse tactic of equational reasoning is \lean{rw} (rewrite). Given a
|
|
|
|
|
|
proven equation, it replaces one side by the other inside your goal:
|
|
|
|
|
|
|
|
|
|
|
|
\begin{lstlisting}[language=Lean]
|
|
|
|
|
|
example (a b : Nat) (h : a = b) : a + a = b + b := by
|
|
|
|
|
|
rw [h] -- goal becomes: b + b = b + b, closed by rfl automatically
|
|
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
|
|
|
|
|
|
Chains of rewrites read like the two-column proofs of school geometry,
|
|
|
|
|
|
except a machine checks every line. Here is commutativity-and-associativity
|
|
|
|
|
|
shuffling, Mathlib lemmas by name:
|
|
|
|
|
|
|
|
|
|
|
|
\begin{lstlisting}[language=Lean]
|
|
|
|
|
|
example (a b c : Nat) : a + b + c = c + b + a := by
|
|
|
|
|
|
rw [Nat.add_comm a b] -- b + a + c = c + b + a
|
|
|
|
|
|
rw [Nat.add_assoc] -- b + (a + c) = c + b + a
|
|
|
|
|
|
rw [Nat.add_comm a c] -- b + (c + a) = c + b + a
|
|
|
|
|
|
rw [← Nat.add_assoc] -- b + c + a = c + b + a
|
|
|
|
|
|
rw [Nat.add_comm b c] -- done
|
|
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
|
|
|
|
|
|
The arrow \(\leftarrow\) rewrites right-to-left. Nobody enjoys writing five-line
|
|
|
|
|
|
shuffles like this, which is exactly why Chapter~\ref{ch:automation}
|
|
|
|
|
|
introduces \lean{ring} --- but you must \emph{once} feel the manual version to
|
|
|
|
|
|
understand what the automation is doing on your behalf.
|
|
|
|
|
|
|
|
|
|
|
|
\section{Induction: the tactic that conquers infinity}
|
|
|
|
|
|
|
|
|
|
|
|
Remember the embarrassment of Chapter~\ref{ch:pat}: \lean{0 + n = n} does not
|
|
|
|
|
|
hold by computation. Now we can prove it --- by induction, the proof
|
|
|
|
|
|
technique that inductive types were born for:
|
|
|
|
|
|
|
|
|
|
|
|
\begin{lstlisting}[language=Lean]
|
|
|
|
|
|
theorem zero_add (n : Nat) : 0 + n = n := by
|
|
|
|
|
|
induction n with
|
|
|
|
|
|
| zero => rfl -- 0 + 0 = 0: computes
|
|
|
|
|
|
| succ k ih => rw [Nat.add_succ, ih]
|
|
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
|
|
|
|
|
|
The \lean{induction} tactic converts a statement about \emph{all} naturals
|
|
|
|
|
|
into two finite obligations: the statement for \lean{zero}, and the statement
|
|
|
|
|
|
for \lean{succ k} \emph{assuming it for} \lean{k} (the induction hypothesis
|
|
|
|
|
|
\lean{ih}). Because every natural number is built from those two
|
|
|
|
|
|
constructors, the two cases cover infinity.
|
|
|
|
|
|
|
Major didactic overhaul: pen-and-paper worked examples + in-book solution pathways, 2x volume (53 -> 106 pages)
- pen-and-paper worked examples in all 12 chapters, using the REAL
constants throughout: 2^-64 waiting-time arithmetic, headroom budgets,
hand type-checking, rfl traces, full goal-state boards, the column-sum
audit at 2^54, inverting 19 mod p via Euclid, the x19 fold at real
weights, denoting p itself (telescope), the 16p audit (8 fails by 151),
the 254+11 inversion-chain bookkeeping, the substitution test, sizing
the 28-vs-1000 extraction, cofactor/torsion arithmetic, and the full
Bernstein-Lange completeness derivation
- CORRECTNESS FIX: ch7 asserted a false factorization of p-1; replaced
with the computationally verified p-1 = 2^2 * 3 * 65147 * Q (Q 71-digit
prime), witness w=2 verified for all four Pratt conditions
- every chapter's exercises now followed immediately by 'Solutions and
pathways' (pathway first, then answer), incl. new exercises
- NEW Interlude: a complete two-clause verification done entirely by
hand, then mapped line-by-line onto the compiled Lean proof
- NEW appendices: A pen-and-paper toolkit (8 recipe cards + drills +
answers), B guided walkthroughs of every exercise-file hole, C tour of
the real repositories; plus glossary, instructor notes, 13-week plan
- preamble: worked-example box, solution macros, math-safe inline code
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 08:55:00 +00:00
|
|
|
|
\begin{worked}{the full board of \lean{zero\_add} --- every goal state, by hand}
|
|
|
|
|
|
Reading a finished tactic proof is like reading a chess score without a
|
|
|
|
|
|
board. Here is the same proof \emph{with} the board: every goal state
|
|
|
|
|
|
written out, exactly as the editor would show it. Reproduce this trace on
|
|
|
|
|
|
paper until the transitions feel inevitable --- it is the core skill of
|
|
|
|
|
|
this chapter. We prove \lean{0 + n = n}, where \lean{+} recurses on its
|
|
|
|
|
|
second argument (Chapter~\ref{ch:lean}).
|
|
|
|
|
|
|
|
|
|
|
|
\smallskip
|
|
|
|
|
|
\noindent After \lean{induction n with}, two boards appear.
|
|
|
|
|
|
\emph{Case} \lean{zero}:
|
|
|
|
|
|
\begin{lstlisting}
|
|
|
|
|
|
⊢ 0 + 0 = 0
|
|
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
The second argument is the literal \lean{0}, so the first defining
|
|
|
|
|
|
equation fires: \lean{0 + 0} \emph{computes} to \lean{0}. Both sides are
|
|
|
|
|
|
now the same term; \lean{rfl} closes the board. (Compare the worked
|
|
|
|
|
|
example in Chapter~\ref{ch:pat}: this is the ``computation sees it'' half.)
|
|
|
|
|
|
|
|
|
|
|
|
\smallskip
|
|
|
|
|
|
\noindent\emph{Case} \lean{succ}: the board now carries an assumption ---
|
|
|
|
|
|
the induction hypothesis:
|
|
|
|
|
|
\begin{lstlisting}
|
|
|
|
|
|
k : Nat
|
|
|
|
|
|
ih : 0 + k = k
|
|
|
|
|
|
⊢ 0 + (k + 1) = k + 1
|
|
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
The left side is \lean{add 0 (succ k)}; the \emph{second} defining
|
|
|
|
|
|
equation fires and rewrites it to \lean{succ (0 + k)}. That step is the
|
|
|
|
|
|
tactic \lean{rw [Nat.add_succ]} (or one layer of
|
|
|
|
|
|
\lean{simp only [Nat.add]}), and the board becomes:
|
|
|
|
|
|
\begin{lstlisting}
|
|
|
|
|
|
k : Nat
|
|
|
|
|
|
ih : 0 + k = k
|
|
|
|
|
|
⊢ (0 + k) + 1 = k + 1
|
|
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
Now the subterm \lean{0 + k} is \emph{exactly} the left side of \lean{ih}.
|
|
|
|
|
|
Rewriting with \lean{rw [ih]} replaces it:
|
|
|
|
|
|
\begin{lstlisting}
|
|
|
|
|
|
k : Nat
|
|
|
|
|
|
ih : 0 + k = k
|
|
|
|
|
|
⊢ k + 1 = k + 1
|
|
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
Identical sides --- \lean{rw} auto-closes with \lean{rfl}. Done.
|
|
|
|
|
|
|
|
|
|
|
|
\smallskip
|
|
|
|
|
|
Two habits to take from this trace. First, at every step ask ``which
|
|
|
|
|
|
defining equation \emph{can} fire, and on which subterm?'' --- that
|
|
|
|
|
|
question, not tactic names, is what drives the proof. Second, notice
|
|
|
|
|
|
where the induction hypothesis earned its keep: computation alone got
|
|
|
|
|
|
stuck at \lean{0 + k} (opaque variable --- Chapter~\ref{ch:pat}'s blocked
|
|
|
|
|
|
reduction), and \lean{ih} is precisely the permission to cross that gap.
|
|
|
|
|
|
An induction proof is computation, plus permission slips at the stuck
|
|
|
|
|
|
points.
|
|
|
|
|
|
\end{worked}
|
|
|
|
|
|
|
2026-07-03 07:44:40 +00:00
|
|
|
|
\begin{aha}
|
|
|
|
|
|
Induction is not a new axiom to swallow --- it falls out of the inductive
|
|
|
|
|
|
definition of \lean{Nat} itself. ``Every \lean{Nat} is \lean{zero} or a
|
|
|
|
|
|
\lean{succ}'' \emph{is} the license to do case analysis; recursion on the
|
|
|
|
|
|
structure \emph{is} the induction. Data and proof principle are two views of
|
|
|
|
|
|
the same declaration. This is Curry--Howard paying rent again.
|
|
|
|
|
|
\end{aha}
|
|
|
|
|
|
|
book overhaul moves 3-5: hook transplants, suspense mechanics, voice unification
Per the 7-reader didactic panel and BOOK-OVERHAUL-PLAN.md:
- front matter: box legend demoted below a lived example (the aha box
becomes its own legend entry)
- ch04: open on the stake (proof the size of a compiler), new section
'When you get stuck --- and you will' promoting the debugging session,
checkpoint now carries the omega cliffhanger forward
- ch06: open on the dare (invert 19 mod a 77-digit prime, two-digit
numbers only), machine-referee #eval after the Euclid box, checkpoint
distills the constant-time trade into one quotable sentence
- ch10: cold-open on the 12 GB crash, spec vocabulary re-armed at the
summit statement, falsification tryit after the 16p box (the -151
#eval), wall dispatch tied to the cold open, closing paragraph places
the certificate in the live log
- ch12: opening pyramid figure now carries question marks resolved
layer by layer through the chapter (suspense instead of spoiler),
kernel-wall rendered as a scene, 'Where you come in' promoted to its
own subsection, false 'closing chapter' removed
- appendix-toolkit: opens in the design-review room, Drill 7b (parity
argument), street assignment close
- appendix-walkthroughs: opens at the reader's low point, one-hole-one-
paragraph contract, counts replaced by 'trust the folder'
- appendix-repo-tour: active three-promise opener, sabotage-the-button
tryit, final tour stop at the transparency log
Build verified: tectonic clean, 118 pages, zero unresolved refs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-07 22:38:44 +00:00
|
|
|
|
\section{When you get stuck --- and you will}
|
|
|
|
|
|
|
|
|
|
|
|
No chapter on tactics is honest without this section. The steady march of
|
|
|
|
|
|
examples above is what proving looks like \emph{afterwards}, cleaned up for
|
|
|
|
|
|
print. What it looks like \emph{during} is the next box --- and the
|
|
|
|
|
|
discipline it teaches is worth more than any tactic in the table.
|
|
|
|
|
|
|
Major didactic overhaul: pen-and-paper worked examples + in-book solution pathways, 2x volume (53 -> 106 pages)
- pen-and-paper worked examples in all 12 chapters, using the REAL
constants throughout: 2^-64 waiting-time arithmetic, headroom budgets,
hand type-checking, rfl traces, full goal-state boards, the column-sum
audit at 2^54, inverting 19 mod p via Euclid, the x19 fold at real
weights, denoting p itself (telescope), the 16p audit (8 fails by 151),
the 254+11 inversion-chain bookkeeping, the substitution test, sizing
the 28-vs-1000 extraction, cofactor/torsion arithmetic, and the full
Bernstein-Lange completeness derivation
- CORRECTNESS FIX: ch7 asserted a false factorization of p-1; replaced
with the computationally verified p-1 = 2^2 * 3 * 65147 * Q (Q 71-digit
prime), witness w=2 verified for all four Pratt conditions
- every chapter's exercises now followed immediately by 'Solutions and
pathways' (pathway first, then answer), incl. new exercises
- NEW Interlude: a complete two-clause verification done entirely by
hand, then mapped line-by-line onto the compiled Lean proof
- NEW appendices: A pen-and-paper toolkit (8 recipe cards + drills +
answers), B guided walkthroughs of every exercise-file hole, C tour of
the real repositories; plus glossary, instructor notes, 13-week plan
- preamble: worked-example box, solution macros, math-safe inline code
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 08:55:00 +00:00
|
|
|
|
\begin{worked}{a debugging session, reconstructed honestly}
|
|
|
|
|
|
Here is a stuck proof, exactly as it happens to everyone, worked
|
|
|
|
|
|
through with the discipline this chapter preaches. Goal: every number
|
|
|
|
|
|
is at most its double --- \lean{∀ n : Nat, n ≤ 2 * n}. Attempt one:
|
|
|
|
|
|
\begin{lstlisting}[language=Lean]
|
|
|
|
|
|
theorem le_double (n : Nat) : n ≤ 2 * n := by
|
|
|
|
|
|
induction n with
|
|
|
|
|
|
| zero => rfl -- fine: 0 ≤ 0 checks
|
|
|
|
|
|
| succ k ih => rw [ih] -- ERROR
|
|
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
The error says \lean{rw} failed: \lean{ih} is
|
|
|
|
|
|
\lean{k ≤ 2 * k} --- an \emph{inequality}, and \lean{rw} rewrites with
|
|
|
|
|
|
\emph{equations} only. First lesson banked: the tactic wasn't wrong,
|
|
|
|
|
|
the \emph{move category} was --- inequalities compose by transitivity
|
|
|
|
|
|
and monotonicity, not substitution. Attempt two, reading the goal
|
|
|
|
|
|
state first this time:
|
|
|
|
|
|
\begin{lstlisting}
|
|
|
|
|
|
k : Nat
|
|
|
|
|
|
ih : k ≤ 2 * k
|
|
|
|
|
|
⊢ k + 1 ≤ 2 * (k + 1)
|
|
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
Plan on paper before touching the keyboard: $2(k+1) = 2k + 2$, and from
|
|
|
|
|
|
\lean{ih}, $k + 1 \le 2k + 1 \le 2k + 2$ ✓ --- a two-step transitivity
|
|
|
|
|
|
chain. That \emph{plan} is provable many ways
|
|
|
|
|
|
(\lean{calc}, \lean{Nat.succ_le_succ} plus lemmas)\dots{} at which
|
|
|
|
|
|
point the honest practitioner pauses: hypotheses and goal are all
|
|
|
|
|
|
\emph{linear arithmetic}. The entire induction was unnecessary:
|
|
|
|
|
|
\begin{lstlisting}[language=Lean]
|
|
|
|
|
|
theorem le_double (n : Nat) : n ≤ 2 * n := by omega
|
|
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
Third lesson, the big one: getting stuck is often the discovery that
|
|
|
|
|
|
you are proving something in the wrong \emph{fragment} --- and the next
|
|
|
|
|
|
chapter is precisely the field guide to fragments. Keep the session's
|
|
|
|
|
|
order of operations, though, because it generalizes: (1) read what the
|
|
|
|
|
|
error says about the move category; (2) write the goal state and plan
|
|
|
|
|
|
on paper; (3) only then ask whether a decision procedure owns the whole
|
|
|
|
|
|
goal. Ten seconds of (3) before an hour of (2) is the professional's
|
|
|
|
|
|
cheat --- but (2) is what makes you able to survive when (3) says no.
|
|
|
|
|
|
\end{worked}
|
|
|
|
|
|
|
2026-07-03 07:44:40 +00:00
|
|
|
|
\begin{pitfall}
|
|
|
|
|
|
When a proof gets stuck, resist the urge to try random tactics --- the
|
|
|
|
|
|
formal-methods equivalent of mashing buttons. The goal state is telling you
|
|
|
|
|
|
something. Three honest questions unstick most situations: (1)~Is the
|
|
|
|
|
|
statement actually true as written --- check a small example with
|
|
|
|
|
|
\lean{\#eval}! (2)~Am I missing a hypothesis --- is there an unstated bound or
|
|
|
|
|
|
nonzero condition? (3)~Is my induction on the right variable? In the real
|
|
|
|
|
|
projects behind this book, ``the proof is stuck'' was, more often than not,
|
|
|
|
|
|
the \emph{statement} being subtly wrong --- a truncated subtraction, a missing
|
|
|
|
|
|
bound. The proof assistant was the messenger.
|
|
|
|
|
|
\end{pitfall}
|
|
|
|
|
|
|
|
|
|
|
|
\section{Structuring real proofs: \texttt{have} and \texttt{calc}}
|
|
|
|
|
|
|
|
|
|
|
|
Big proofs are not flat lists of tactics; they are structured arguments with
|
|
|
|
|
|
named intermediate results. The \lean{have} tactic states and proves a
|
|
|
|
|
|
stepping stone; \lean{calc} lays out a chain of equalities or inequalities
|
|
|
|
|
|
the way you would on a whiteboard:
|
|
|
|
|
|
|
|
|
|
|
|
\begin{lstlisting}[language=Lean]
|
|
|
|
|
|
example (a b : Nat) (h : a = 2 * b) : a + a = 4 * b := by
|
|
|
|
|
|
have h2 : a + a = 2 * a := by rw [Nat.two_mul]
|
|
|
|
|
|
calc a + a = 2 * a := h2
|
|
|
|
|
|
_ = 2 * (2 * b) := by rw [h]
|
|
|
|
|
|
_ = 4 * b := by rw [← Nat.mul_assoc]
|
|
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
|
Major didactic overhaul: pen-and-paper worked examples + in-book solution pathways, 2x volume (53 -> 106 pages)
- pen-and-paper worked examples in all 12 chapters, using the REAL
constants throughout: 2^-64 waiting-time arithmetic, headroom budgets,
hand type-checking, rfl traces, full goal-state boards, the column-sum
audit at 2^54, inverting 19 mod p via Euclid, the x19 fold at real
weights, denoting p itself (telescope), the 16p audit (8 fails by 151),
the 254+11 inversion-chain bookkeeping, the substitution test, sizing
the 28-vs-1000 extraction, cofactor/torsion arithmetic, and the full
Bernstein-Lange completeness derivation
- CORRECTNESS FIX: ch7 asserted a false factorization of p-1; replaced
with the computationally verified p-1 = 2^2 * 3 * 65147 * Q (Q 71-digit
prime), witness w=2 verified for all four Pratt conditions
- every chapter's exercises now followed immediately by 'Solutions and
pathways' (pathway first, then answer), incl. new exercises
- NEW Interlude: a complete two-clause verification done entirely by
hand, then mapped line-by-line onto the compiled Lean proof
- NEW appendices: A pen-and-paper toolkit (8 recipe cards + drills +
answers), B guided walkthroughs of every exercise-file hole, C tour of
the real repositories; plus glossary, instructor notes, 13-week plan
- preamble: worked-example box, solution macros, math-safe inline code
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 08:55:00 +00:00
|
|
|
|
\begin{worked}{planning a \lean{calc} on paper --- backwards from the target}
|
|
|
|
|
|
Professionals do not type a \lean{calc} top-to-bottom and hope; they plan
|
|
|
|
|
|
it on paper, usually \emph{backwards}. Watch the method on the real
|
|
|
|
|
|
reduction identity from the Ed25519 code (Chapter~\ref{ch:modular} proves
|
|
|
|
|
|
the ingredients): given a 256-bit value split as
|
|
|
|
|
|
$x = x_{\mathrm{lo}} + 2^{255} x_{\mathrm{hi}}$, the code returns
|
|
|
|
|
|
$x_{\mathrm{lo}} + 19 x_{\mathrm{hi}}$, and we owe
|
|
|
|
|
|
\[
|
|
|
|
|
|
x_{\mathrm{lo}} + 19\, x_{\mathrm{hi}}
|
|
|
|
|
|
\;\equiv\;
|
|
|
|
|
|
x \pmod{p}.
|
|
|
|
|
|
\]
|
|
|
|
|
|
Plan backwards: the target's right side is $x$, which we only know through
|
|
|
|
|
|
its \emph{definition}, so the last line of the chain will be
|
|
|
|
|
|
``$\ldots = x_{\mathrm{lo}} + 2^{255} x_{\mathrm{hi}} = x$ by the split.''
|
|
|
|
|
|
What could precede it? Something that turns $19$ into $2^{255}$: the fact
|
|
|
|
|
|
$19 \equiv 2^{255}$, i.e.\ the constant identity $2^{255} - 19 = p
|
|
|
|
|
|
\equiv 0$. So the middle step is a congruence rewrite, and the paper plan
|
|
|
|
|
|
reads, bottom to top:
|
|
|
|
|
|
\[
|
|
|
|
|
|
\begin{array}{lll}
|
|
|
|
|
|
\text{(3)} & x_{\mathrm{lo}} + 2^{255} x_{\mathrm{hi}} = x & \text{definition of the split}\\
|
|
|
|
|
|
\text{(2)} & x_{\mathrm{lo}} + 19\, x_{\mathrm{hi}} \equiv x_{\mathrm{lo}} + 2^{255} x_{\mathrm{hi}} & \text{since } 19 \equiv 2^{255} \pmod p\\
|
|
|
|
|
|
\text{(1)} & \text{start: } x_{\mathrm{lo}} + 19\, x_{\mathrm{hi}} & \\
|
|
|
|
|
|
\end{array}
|
|
|
|
|
|
\]
|
|
|
|
|
|
Reverse it, and the \lean{calc} types itself --- each line's justification
|
|
|
|
|
|
was decided \emph{before} any Lean was written. The habit scales: the real
|
|
|
|
|
|
multiplication proof in \code{dalek-ed25519-verified} was planned exactly
|
|
|
|
|
|
this way, as a page of paper algebra whose lines became \lean{have}s. When
|
|
|
|
|
|
you cannot plan the chain on paper, you are not ready to type it; the
|
|
|
|
|
|
proof assistant checks reasoning, it does not supply it.
|
|
|
|
|
|
\end{worked}
|
|
|
|
|
|
|
2026-07-03 07:44:40 +00:00
|
|
|
|
This style is not cosmetic. In the verified field arithmetic you will read
|
|
|
|
|
|
later, a single multiplication correctness proof is a \lean{calc} chain
|
|
|
|
|
|
tracking limb products through carries --- dozens of steps, each trivial,
|
|
|
|
|
|
whose \emph{composition} is the theorem. \lean{have} and \lean{calc} are how
|
|
|
|
|
|
proofs stay readable at that scale; they are also how they stay
|
|
|
|
|
|
\emph{maintainable}, because a broken step localizes the damage to one line.
|
|
|
|
|
|
|
|
|
|
|
|
There is one more structuring fact worth knowing early, because it saved the
|
|
|
|
|
|
real project from a crash-course (literally --- see
|
|
|
|
|
|
Chapter~\ref{ch:honesty}): breaking a proof into small named \lean{have}
|
|
|
|
|
|
steps also controls the proof assistant's \emph{memory appetite}. A monolithic
|
|
|
|
|
|
``figure it all out at once'' tactic call over a huge context can consume
|
|
|
|
|
|
gigabytes; ten targeted steps, pennies each, prove the same thing. Structure
|
|
|
|
|
|
is not just style --- it is engineering.
|
|
|
|
|
|
|
|
|
|
|
|
\begin{tryit}
|
|
|
|
|
|
Open \code{exercises/Ch04.lean}. It sets up each theorem with the goal state
|
|
|
|
|
|
drawn in a comment, then asks you to: prove \lean{and_swap} in tactic mode;
|
|
|
|
|
|
prove \lean{zero_add} \emph{without} peeking above; and repair a broken
|
|
|
|
|
|
\lean{calc} chain in which exactly one step is wrong. The third
|
|
|
|
|
|
exercise is secretly the most realistic job training in this book.
|
|
|
|
|
|
\end{tryit}
|
|
|
|
|
|
|
|
|
|
|
|
\section*{Exercises}
|
|
|
|
|
|
|
|
|
|
|
|
\exercise{Prove by induction: \lean{∀ n : Nat, n + 0 = n} and
|
|
|
|
|
|
\lean{∀ n m : Nat, n + succ m = succ (n + m)}. (These are the mirror images
|
|
|
|
|
|
of the definitional equations --- the ones computation gives you for free ---
|
|
|
|
|
|
and together they yield commutativity.)}
|
|
|
|
|
|
|
|
|
|
|
|
\exercise{Using the previous exercise, prove
|
|
|
|
|
|
\lean{∀ n m : Nat, n + m = m + n} by induction on \lean{m}. Write out, in
|
|
|
|
|
|
one prose sentence per case, what each branch of your proof says.}
|
|
|
|
|
|
|
|
|
|
|
|
\exercise{Prove \lean{∀ n : Nat, 2 * n = n + n} twice: once with
|
|
|
|
|
|
\lean{induction}, once with a single \lean{rw} using a Mathlib lemma you find
|
|
|
|
|
|
yourself (search hint: \lean{exact?} asks Lean to search for you).}
|
|
|
|
|
|
|
|
|
|
|
|
\exercise{(Reading) In the goal state
|
|
|
|
|
|
\lean{h : a < 2\textasciicircum{}51 ⊢ a * 19 < 2\textasciicircum{}56}, no induction is needed --- this is pure
|
|
|
|
|
|
arithmetic. Which tactic from the table would you \emph{guess} handles it?
|
|
|
|
|
|
(Answer next chapter; your guess is the point.)}
|
|
|
|
|
|
|
Major didactic overhaul: pen-and-paper worked examples + in-book solution pathways, 2x volume (53 -> 106 pages)
- pen-and-paper worked examples in all 12 chapters, using the REAL
constants throughout: 2^-64 waiting-time arithmetic, headroom budgets,
hand type-checking, rfl traces, full goal-state boards, the column-sum
audit at 2^54, inverting 19 mod p via Euclid, the x19 fold at real
weights, denoting p itself (telescope), the 16p audit (8 fails by 151),
the 254+11 inversion-chain bookkeeping, the substitution test, sizing
the 28-vs-1000 extraction, cofactor/torsion arithmetic, and the full
Bernstein-Lange completeness derivation
- CORRECTNESS FIX: ch7 asserted a false factorization of p-1; replaced
with the computationally verified p-1 = 2^2 * 3 * 65147 * Q (Q 71-digit
prime), witness w=2 verified for all four Pratt conditions
- every chapter's exercises now followed immediately by 'Solutions and
pathways' (pathway first, then answer), incl. new exercises
- NEW Interlude: a complete two-clause verification done entirely by
hand, then mapped line-by-line onto the compiled Lean proof
- NEW appendices: A pen-and-paper toolkit (8 recipe cards + drills +
answers), B guided walkthroughs of every exercise-file hole, C tour of
the real repositories; plus glossary, instructor notes, 13-week plan
- preamble: worked-example box, solution macros, math-safe inline code
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 08:55:00 +00:00
|
|
|
|
\section*{Solutions and pathways}
|
|
|
|
|
|
\solutionsintro
|
|
|
|
|
|
|
|
|
|
|
|
\solhead{4.1}
|
|
|
|
|
|
\pathway Before proving anything, predict which facts are \emph{free}:
|
|
|
|
|
|
addition recurses on its second argument, so any statement whose second
|
|
|
|
|
|
argument exhibits a constructor should compute. Both requested statements
|
|
|
|
|
|
--- \lean{n + 0 = n} and \lean{n + succ m = succ (n + m)} --- have
|
|
|
|
|
|
constructor-shaped second arguments (\lean{0} and \lean{succ m}). The
|
|
|
|
|
|
honest content of this exercise is noticing that.
|
|
|
|
|
|
\answer \lean{theorem a : ∀ n : Nat, n + 0 = n := fun n => rfl} --- the
|
|
|
|
|
|
first defining equation. \lean{theorem b : ∀ n m, n + succ m = succ (n+m)
|
|
|
|
|
|
:= fun n m => rfl} --- the second. Neither needs induction; both are the
|
|
|
|
|
|
definitional mirror images of the two facts that \emph{do}
|
|
|
|
|
|
(\lean{0 + n = n}, \lean{succ n + m = succ (n + m)}), which is exactly the
|
|
|
|
|
|
asymmetry the worked example traced. If you reached for \lean{induction}
|
|
|
|
|
|
here, nothing is wrong --- it succeeds --- but recognizing a free fact
|
|
|
|
|
|
saves you thirty seconds a hundred times a day.
|
|
|
|
|
|
|
|
|
|
|
|
\solhead{4.2}
|
|
|
|
|
|
\pathway Induct on \lean{m} (the variable the recursion consumes on the
|
|
|
|
|
|
\emph{right} of \lean{n + m}), so the definitional equations fire on one
|
|
|
|
|
|
side and 4.1's lemmas patch the other. In each case, before touching
|
|
|
|
|
|
tactics, write the goal and ask: which side steps by definition, which
|
|
|
|
|
|
needs a lemma?
|
|
|
|
|
|
\answer
|
|
|
|
|
|
\begin{lstlisting}[language=Lean]
|
|
|
|
|
|
theorem add_comm' (n m : Nat) : n + m = m + n := by
|
|
|
|
|
|
induction m with
|
|
|
|
|
|
| zero => rw [Nat.add_zero, Nat.zero_add]
|
|
|
|
|
|
| succ k ih => rw [Nat.add_succ, Nat.succ_add, ih]
|
|
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
Prose, one sentence per case, as requested. \emph{Zero case:} ``$n + 0$ is
|
|
|
|
|
|
$n$ by definition, and $0 + n$ is $n$ by the mirror lemma, so both sides
|
|
|
|
|
|
are $n$.'' \emph{Successor case:} ``both sides compute to a successor ---
|
|
|
|
|
|
the left by the defining equation, the right by the mirror lemma --- and
|
|
|
|
|
|
under the \lean{succ} the two sides are the induction hypothesis.'' Note
|
|
|
|
|
|
the architecture: two definitional equations, two mirror lemmas, one
|
|
|
|
|
|
induction --- commutativity is not one fact but a small \emph{ecosystem},
|
|
|
|
|
|
and you have now built all of it from bare constructors.
|
|
|
|
|
|
|
|
|
|
|
|
\solhead{4.3}
|
|
|
|
|
|
\pathway For the induction route, the \lean{succ} case needs
|
|
|
|
|
|
$2(k+1) = (k+1) + (k+1)$ reorganized into the induction hypothesis's shape
|
|
|
|
|
|
plus successors --- expect two rewrites. For the library route, the skill
|
|
|
|
|
|
is \emph{search}: place the cursor on the goal and run \lean{exact?}.
|
|
|
|
|
|
\answer Induction:
|
|
|
|
|
|
\begin{lstlisting}[language=Lean]
|
|
|
|
|
|
theorem two_mul' (n : Nat) : 2 * n = n + n := by
|
|
|
|
|
|
induction n with
|
|
|
|
|
|
| zero => rfl
|
|
|
|
|
|
| succ k ih => rw [Nat.mul_succ, ih, Nat.succ_add, Nat.add_succ]
|
|
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
Library: \lean{exact?} finds \lean{Nat.two_mul}, so
|
|
|
|
|
|
\lean{theorem two_mul'' (n : Nat) : 2 * n = n + n := Nat.two_mul n}. Both
|
|
|
|
|
|
are legitimate craft: the first when you are building the ecosystem, the
|
|
|
|
|
|
second when you are using it. Mathlib has over 200{,}000 lemmas ---
|
|
|
|
|
|
searching \emph{is} a proof technique, and \lean{exact?} is its tactic.
|
|
|
|
|
|
|
|
|
|
|
|
\solhead{4.4}
|
|
|
|
|
|
\pathway The goal mixes a hypothesis bound, multiplication by a
|
|
|
|
|
|
\emph{constant}, and powers of two --- inspect the table: nothing fits
|
|
|
|
|
|
perfectly, which is the setup's point. What you want is a decision
|
|
|
|
|
|
procedure for linear arithmetic.
|
|
|
|
|
|
\answer The intended guess is \lean{simp} or \lean{rw}-with-lemmas ---
|
|
|
|
|
|
and the intended discovery is that neither is pleasant. The actual answer,
|
|
|
|
|
|
one chapter ahead: \lean{omega}, which decides such goals instantly
|
|
|
|
|
|
because $a \cdot 19$ is \emph{linear} in $a$ (19 is a constant). If you
|
|
|
|
|
|
guessed \lean{omega} from the table's absence, better still: you have
|
|
|
|
|
|
started classifying goals by \emph{logical fragment}, which is precisely
|
|
|
|
|
|
the professional habit Chapter~\ref{ch:automation} installs.
|
|
|
|
|
|
|
2026-07-03 07:44:40 +00:00
|
|
|
|
\begin{checkpoint}
|
|
|
|
|
|
You should now be able to: read a goal state (context, turnstile, goal);
|
|
|
|
|
|
drive the core tactics \lean{intro}, \lean{exact}, \lean{apply},
|
|
|
|
|
|
\lean{cases}, \lean{rw}, \lean{induction}; structure a multi-step argument
|
|
|
|
|
|
with \lean{have} and \lean{calc}; and --- most importantly --- when stuck,
|
book overhaul moves 3-5: hook transplants, suspense mechanics, voice unification
Per the 7-reader didactic panel and BOOK-OVERHAUL-PLAN.md:
- front matter: box legend demoted below a lived example (the aha box
becomes its own legend entry)
- ch04: open on the stake (proof the size of a compiler), new section
'When you get stuck --- and you will' promoting the debugging session,
checkpoint now carries the omega cliffhanger forward
- ch06: open on the dare (invert 19 mod a 77-digit prime, two-digit
numbers only), machine-referee #eval after the Euclid box, checkpoint
distills the constant-time trade into one quotable sentence
- ch10: cold-open on the 12 GB crash, spec vocabulary re-armed at the
summit statement, falsification tryit after the 16p box (the -151
#eval), wall dispatch tied to the cold open, closing paragraph places
the certificate in the live log
- ch12: opening pyramid figure now carries question marks resolved
layer by layer through the chapter (suspense instead of spoiler),
kernel-wall rendered as a scene, 'Where you come in' promoted to its
own subsection, false 'closing chapter' removed
- appendix-toolkit: opens in the design-review room, Drill 7b (parity
argument), street assignment close
- appendix-walkthroughs: opens at the reader's low point, one-hole-one-
paragraph contract, counts replaced by 'trust the folder'
- appendix-repo-tour: active three-promise opener, sabotage-the-button
tryit, final tour stop at the transparency log
Build verified: tectonic clean, 118 pages, zero unresolved refs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-07 22:38:44 +00:00
|
|
|
|
interrogate the \emph{statement} before blaming the proof. One goal from the
|
|
|
|
|
|
exercises is deliberately still open: the bound
|
|
|
|
|
|
$a \cdot 19 < 2^{56}$, which no tactic in this chapter's table owns. Carry it
|
|
|
|
|
|
with you --- the next chapter opens by handing you the tactic that eats it in
|
|
|
|
|
|
one line.
|
2026-07-03 07:44:40 +00:00
|
|
|
|
\end{checkpoint}
|