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.

An example using Coqdoc

This is a hybrid rendering mode: coqdoc is used to render literate comments, and Alectryon is used to render code, responses, and goals. It's a bit as if coqdoc was just a markup language, without anything specific to Coq. Cons:

Some code

Here's an *inductive specification* of evenness:
Inductive Even : nat -> Prop :=
| EvenO : Even O
| EvenS : forall n, Even n -> Even (S (S n)).
… and a corresponding decision procedure:
Fixpoint even (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?

forall n : nat, even n = true <-> Even n

forall n : 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``?
    
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; inversion 1.
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:

forall n : nat, (even n = true <-> Even n) /\ (even (S n) = true <-> Even (S n))

forall n : 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: inversion 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)))
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
inversion 1; eauto. Qed.

Writing a fixpoint

But writing a fixpoint is much nicer:
even_Even_fp:forall n : nat, even n = true <-> Even n
n:nat

even n = true <-> Even n
even_Even_fp:forall n : nat, even n = true <-> Even n
n:nat

even n = true <-> Even n
even_Even_fp:forall n : nat, even n = true <-> Even n

true = true <-> Even 0
even_Even_fp:forall n : nat, even n = true <-> Even n
false = true <-> Even 1
even_Even_fp:forall n : nat, even n = true <-> Even n
n:nat
even n = true <-> Even (S (S n))
even_Even_fp:forall n : nat, even n = true <-> Even n

true = true <-> Even 0
repeat constructor.
even_Even_fp:forall n : nat, even n = true <-> Even n

false = true <-> Even 1
split; inversion 1.
even_Even_fp:forall n : nat, even n = true <-> Even n
n:nat

even n = true <-> Even (S (S n))
even_Even_fp:forall n : nat, even n = true <-> Even n
n:nat

even n = true -> Even (S (S n))
even_Even_fp:forall n : nat, even n = true <-> Even n
n:nat
Even (S (S n)) -> even n = true
even_Even_fp:forall n : nat, even n = true <-> Even n
n:nat

even n = true -> Even (S (S n))
constructor; apply even_Even; assumption.
even_Even_fp:forall n : nat, even n = true <-> Even n
n:nat

Even (S (S n)) -> even n = true
inversion 1; apply even_Even; assumption. Qed.