Built with Alectryon, running Coq+SerAPI. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑Ctrl+↓ to navigate, Ctrl+🖱️ to focus. On Mac, use ⌘ instead of Ctrl.
(*|=================================================================== Forget about strengthening induction hypotheses: write fixpoints!===================================================================Here's an *inductive specification* of evenness:|*)InductiveEven : nat -> Prop :=
| EvenO : Even O
| EvenS : foralln, Even n -> Even (S (S n)).(*|… and a corresponding decision procedure:|*)Fixpointeven (n: nat): bool :=
match n with
| 0 => true
| 1 => false
| S (S n) => even n
end.(* Ensure that we never unfold [even (S n)] *)Arguments even : simpl nomatch.(*|Can we prove it correct?.. coq:: unfold|*)
foralln : nat, even n = true <-> Even n
foralln : nat, even n = true <-> Even n
even 0 = true <-> Even 0
n:nat
IHn:even n = true <-> Even n
even (S n) = true <-> Even (S n)
true = true <-> Even 0
n:nat
IHn:even n = true <-> Even n
even (S n) = true <-> Even (S n)
true = true <-> Even 0
true = true -> Even 0
Even 0 -> true = true
all: constructor.
n:nat
IHn:even n = true <-> Even n
even (S n) = true <-> Even (S n)
In environment
n : nat
IHn : even n = true <-> Even n
H : even n = true -> Even n
Unable to unify"Even n"with"even (S n) = true <-> Even (S n)".
(*|The induction hypothesis doesn't apply — maybe we need to destruct ``n``?.. coq:: unfold|*)
IHn:even 0 = true <-> Even 0
even 1 = true <-> Even 1
n:nat
IHn:even (S n) = true <-> Even (S n)
even (S (S n)) = true <-> Even (S (S n))
IHn:even 0 = true <-> Even 0
even 1 = true <-> Even 1
split; inversion1.
n:nat
IHn:even (S n) = true <-> Even (S n)
even (S (S n)) = true <-> Even (S (S n))
(*|Stuck again!|*)Abort.(*|Strengthening the spec======================The usual approach is to strengthen the spec to work around the weakness of the inductive principle... coq:: unfold|*)
foralln : nat,
(even n = true <-> Even n) /\
(even (S n) = true <-> Even (S n))
foralln : nat,
(even n = true <-> Even n) /\
(even (S n) = true <-> Even (S n))
(true = true <-> Even 0) /\ (false = true <-> Even 1)
n:nat
IHn:(even n = true <-> Even n) /\ (even (S n) = true <-> Even (S n))
(even (S n) = true <-> Even (S n)) /\
(even n = true <-> Even (S (S n)))
(true = true <-> Even 0) /\ (false = true <-> Even 1)
true = true -> Even 0
false = true -> Even 1
Even 1 -> false = true
false = true -> Even 1
Even 1 -> false = true
all: inversion1.
n:nat
IHn:(even n = true <-> Even n) /\ (even (S n) = true <-> Even (S n))
(even (S n) = true <-> Even (S n)) /\
(even n = true <-> Even (S (S n)))
n:nat
Hne:even n = true -> Even n
HnE:Even n -> even n = true
HSne:even (S n) = true -> Even (S n)
HSnE:Even (S n) -> even (S n) = true
(even (S n) = true <-> Even (S n)) /\
(even n = true <-> Even (S (S n)))
n:nat
Hne:even n = true -> Even n
HnE:Even n -> even n = true
HSne:even (S n) = true -> Even (S n)
HSnE:Even (S n) -> even (S n) = true
even (S n) = true -> Even (S n)
n:nat
Hne:even n = true -> Even n
HnE:Even n -> even n = true
HSne:even (S n) = true -> Even (S n)
HSnE:Even (S n) -> even (S n) = true
Even (S n) -> even (S n) = true
n:nat
Hne:even n = true -> Even n
HnE:Even n -> even n = true
HSne:even (S n) = true -> Even (S n)
HSnE:Even (S n) -> even (S n) = true
even n = true -> Even (S (S n))
n:nat
Hne:even n = true -> Even n
HnE:Even n -> even n = true
HSne:even (S n) = true -> Even (S n)
HSnE:Even (S n) -> even (S n) = true
Even (S (S n)) -> even n = true
n:nat
Hne:even n = true -> Even n
HnE:Even n -> even n = true
HSne:even (S n) = true -> Even (S n)
HSnE:Even (S n) -> even (S n) = true
Even (S (S n)) -> even n = true
inversion1; eauto.Qed.(*|Writing a fixpoint==================But writing a fixpoint (either with the :coq:`Fixpoint` command or with the `fix` tactic) is much nicer:.. coq:: unfold|*)
even_Even_fp:foralln : nat,
even n = true <-> Even n
n:nat
even n = true <-> Even n
even_Even_fp:foralln : nat,
even n = true <-> Even n
n:nat
even n = true <-> Even n
even_Even_fp:foralln : nat,
even n = true <-> Even n
true = true <-> Even 0
even_Even_fp:foralln : nat,
even n = true <-> Even n
false = true <-> Even 1
even_Even_fp:foralln : nat,
even n = true <-> Even n
n:nat
even n = true <-> Even (S (S n))
even_Even_fp:foralln : nat,
even n = true <-> Even n
true = true <-> Even 0
repeatconstructor.
even_Even_fp:foralln : nat,
even n = true <-> Even n
false = true <-> Even 1
split; inversion1.
even_Even_fp:foralln : nat,
even n = true <-> Even n
n:nat
even n = true <-> Even (S (S n))
even_Even_fp:foralln : nat,
even n = true <-> Even n
n:nat
even n = true -> Even (S (S n))
even_Even_fp:foralln : nat,
even n = true <-> Even n
n:nat
Even (S (S n)) -> even n = true
even_Even_fp:foralln : nat,
even n = true <-> Even n
n:nat
even n = true -> Even (S (S n))
constructor; apply even_Even_fp; assumption.
even_Even_fp:foralln : nat,
even n = true <-> Even n
n:nat
Even (S (S n)) -> even n = true
inversion1; apply even_Even_fp; assumption.Qed.(*|Note that the standard library already contains a :coqid:`boolean <Coq.Init.Nat.even>` :coqid:`predicate <Coq.Init.Nat#even>` for `even` (called :coqid:`Coq.Init.Nat.even`, or :coqid:`Coq.Init.Nat#even` for short), as well as an :coqid:`inductive one <Coq.Arith.PeanoNat#Nat.Even>` (called :coqid:`Coq.Arith.PeanoNat#Nat.Even` in module :coqid:`Coq.Arith.PeanoNat#`).|*)