Alectryon supports literate programs and documents (combinations of code and prose) written in Coq and reStructuredText. Here is an example, written in Coq. It can be converted to reST, HTML, or LaTeX using the following commands:
alectryon literate_coq.v # Coq+reST → HTML; produces ‘literate_coq.html’ $ DOCUTILSCONFIG=literate.docutils.conf alectryon \ literate_coq.v --backend latex # Coq+reST → LaTeX; produces ‘literate_coq.tex’ alectryon literate_coq.v --backend rst # Coq+reST → reST; produces ‘literate_coq.v.rst’ $ cd ..; python -m alectryon.literate \ recipes/literate_coq.v > recipes/literate_coq.min.rst # Minimal Coq → reST; produces ‘literate_coq.min.rst’ $ cd ..; python -m alectryon.literate --coq2rst - \ < recipes/literate_coq.v > recipes/literate_coq.min.stdin.rst # Minimal Coq → reST; produces ‘literate_coq.min.stdin.rst’
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 nforall n : nat, even n = true <-> Even neven 0 = true <-> Even 0n: nat
IHn: even n = true <-> Even neven (S n) = true <-> Even (S n)true = true <-> Even 0n: nat
IHn: even n = true <-> Even neven (S n) = true <-> Even (S n)true = true <-> Even 0all: constructor.true = true -> Even 0Even 0 -> true = truen: nat
IHn: even n = true <-> Even neven (S n) = true <-> Even (S n)
The induction hypothesis doesn't apply — maybe we need to destruct n?
IHn: even 0 = true <-> Even 0even 1 = true <-> Even 1n: nat
IHn: even (S n) = true <-> Even (S n)even (S (S n)) = true <-> Even (S (S n))split; inversion 1.IHn: even 0 = true <-> Even 0even 1 = true <-> Even 1n: nat
IHn: even (S n) = true <-> Even (S n)even (S (S n)) = true <-> Even (S (S n))
Stuck again!
Abort.
The usual approach is to strengthen the spec to work around the weakness of the inductive principle.
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 0false = true -> Even 1Even 1 -> false = trueall: inversion 1.false = true -> Even 1Even 1 -> false = truen: 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) = trueeven (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) = trueEven (S n) -> even (S n) = truen: 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) = trueeven 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) = trueEven (S (S n)) -> even n = trueinversion 1; eauto. Qed.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) = trueEven (S (S n)) -> even n = true
But writing a fixpoint (either with the Fixpoint
command or with the fix
tactic) is much nicer:
even_Even_fp: forall n : nat, even n = true <-> Even n
n: nateven n = true <-> Even neven_Even_fp: forall n : nat, even n = true <-> Even n
n: nateven n = true <-> Even neven_Even_fp: forall n : nat, even n = true <-> Even ntrue = true <-> Even 0even_Even_fp: forall n : nat, even n = true <-> Even nfalse = true <-> Even 1even_Even_fp: forall n : nat, even n = true <-> Even n
n: nateven n = true <-> Even (S (S n))repeat constructor.even_Even_fp: forall n : nat, even n = true <-> Even ntrue = true <-> Even 0split; inversion 1.even_Even_fp: forall n : nat, even n = true <-> Even nfalse = true <-> Even 1even_Even_fp: forall n : nat, even n = true <-> Even n
n: nateven n = true <-> Even (S (S n))even_Even_fp: forall n : nat, even n = true <-> Even n
n: nateven n = true -> Even (S (S n))even_Even_fp: forall n : nat, even n = true <-> Even n
n: natEven (S (S n)) -> even n = trueconstructor; apply even_Even_fp; assumption.even_Even_fp: forall n : nat, even n = true <-> Even n
n: nateven n = true -> Even (S (S n))inversion 1; apply even_Even_fp; assumption. Qed.even_Even_fp: forall n : nat, even n = true <-> Even n
n: natEven (S (S n)) -> even n = true
Alectryon defined a :coqid: role to link to definitions in Coqdoc-generated documentation; for example:
Note that the standard library already contains a boolean predicate for even
(called Coq.Init.Nat.even, or even for short), as well as an inductive one (called Nat.Even in module Coq.Arith.PeanoNat).
If you have your own documentation, you can use a custom role to point to your own URL:
With this definition, for example, you can write Nat.Even instead of Nat.Even.