Open Scope string_scope. Require Import List. Import ListNotations. Open Scope list_scope.
Inductive expr : Type := | Const : nat -> expr | Var : string -> expr | Plus : expr -> expr -> expr | Mult : expr -> expr -> expr. Fixpoint eval (env : string -> nat) (e : expr) : nat := match e with | Const n => n | Var x => env x | Plus e1 e2 => eval env e1 + eval env e2 | Mult e1 e2 => eval env e1 * eval env e2 end.
A simple imperative programming language
Inductive stmt :=
  | Assign : string -> expr -> stmt
  | Seq : stmt -> stmt -> stmt
  | If : expr -> stmt -> stmt -> stmt
  | Repeat : expr -> stmt -> stmt.Iterate a function n times
Fixpoint iter {A} (f : A -> A) (n : nat) (x : A) : A :=
  match n with
  | 0 => x
  | S n => f (iter f n x)
  end.Evaluate a statement
Fixpoint eval_stmt (env : string -> nat) (stmt : stmt) : string -> nat :=
  match stmt with
  | Assign x e => 
    let v := eval env e in
    fun var => if String.eqb x var then v else env var
  | Seq s1 s2 => 
    let env' := eval_stmt env s1 in
    eval_stmt env' s2
  | If e stmt1 stmt2 => 
    let v := eval env e in
    if Nat.eqb v 0 then eval_stmt env stmt1 else eval_stmt env stmt2
  | Repeat e body => 
    let v := eval env e in
    iter (fun env => eval_stmt env body) v env
  end.Example
Definition s := Repeat (Var "x") (Repeat (Var "x") (Assign "y" (Plus (Var "y") (Const 1)))).
Now we try and add While loops
Inductive stmt' := | Assign' : string -> expr -> stmt' | Seq' : stmt' -> stmt' -> stmt' | If' : expr -> stmt' -> stmt' -> stmt' | Repeat' : expr -> stmt' -> stmt' | While' : expr -> stmt' -> stmt'. Fixpoint eval_stmt' (env : string -> nat) (stmt : stmt') : string -> nat := match stmt with | Assign' x e => let v := eval env e in fun var => if String.eqb x var then v else env var | Seq' s1 s2 => let env' := eval_stmt' env s1 in eval_stmt' env' s2 | If' e stmt1 stmt2 => let v := eval env e in if Nat.eqb v 0 then eval_stmt' env stmt1 else eval_stmt' env stmt2 | Repeat' e body => let v := eval env e in iter (fun env => eval_stmt' env body) v env | While' e body => let v := eval env e in if Nat.eqb v 0 then env else let env' := eval_stmt' env body in env' (* Want: eval_stmt' env' (While' e body) *) end.
Adding while loops breaks the termination checker.
Indeed, while loops don't always terminate!
We need a different approach for defining the semantics of while loops.
We'll use inductive relations.
Fixpoint is_even (n:nat) : Prop := match n with | 0 => True | S n' => match n' with | 0 => False | S n'' => is_even n'' end end.is_even 16constructor. Qed. Inductive even : nat -> Prop := | even_0 : even 0 | even_SS : forall n, even n -> even (S (S n)).is_even 16even 4even 4even 2apply even_0. Qed.even 0n: nateven n -> even (4 + n)n: nateven n -> even (4 + n)n: nat
H: even neven (4 + n)n: nat
H: even neven (S (S n))apply H. Qed.n: nat
H: even neven nn: nateven (S (S n)) -> even nn: nateven (S (S n)) -> even nn: nat
H: even (S (S n))even napply H1. Qed.n: nat
H: even (S (S n))
n0: nat
H1: even n
H0: n0 = neven n~ even 1~ even 1inversion H. Qed.H: even 1False~ even 3~ even 3H: even 3FalseH: even 3
n: nat
H1: even 1
H0: n = 1Falseapply H1. Qed. Require Import Arith. Require Import Lia.H: even 3
n: nat
H1: even 1
H0: n = 1even 1n: nateven (2 * n)n: nateven (2 * n)even (2 * 0)n: nat
IHn: even (2 * n)even (2 * S n)apply even_0.even (2 * 0)n: nat
IHn: even (2 * n)even (2 * S n)n: nat
IHn: even (2 * n)even (2 + 2 * n)apply IHn. Qed.n: nat
IHn: even (2 * n)even (2 * n)n: nateven n -> exists k : nat, n = 2 * kn: nateven n -> exists k : nat, n = 2 * kn: nat
H: even nexists k : nat, n = 2 * kH: even 0exists k : nat, 0 = 2 * kn: nat
H: even (S n)
IHn: even n -> exists k : nat, n = 2 * kexists k : nat, S n = 2 * kH: even 0exists k : nat, 0 = 2 * kreflexivity.H: even 00 = 2 * 0(* We're stuck: we need `even n` to use the IHn, but we have `even (S n)`, so n is not even! *) Abort.n: nat
H: even (S n)
IHn: even n -> exists k : nat, n = 2 * kexists k : nat, S n = 2 * kn: nateven n -> exists k : nat, n = 2 * k(* We use strong induction. *)n: nateven n -> exists k : nat, n = 2 * kn: nat
H: even nexists k : nat, n = 2 * kn: nat
H: even n
H0: forall m : nat, m < n -> even m -> exists k : nat, m = 2 * kexists k : nat, n = 2 * kH: even 0
H0: forall m : nat, m < 0 -> even m -> exists k : nat, m = 2 * kexists k : nat, 0 = 2 * kn: nat
H: even (S n)
H0: forall m : nat, m < S n -> even m -> exists k : nat, m = 2 * kexists k : nat, S n = 2 * kH: even 0
H0: forall m : nat, m < 0 -> even m -> exists k : nat, m = 2 * kexists k : nat, 0 = 2 * kreflexivity.H: even 0
H0: forall m : nat, m < 0 -> even m -> exists k : nat, m = 2 * k0 = 2 * 0n: nat
H: even (S n)
H0: forall m : nat, m < S n -> even m -> exists k : nat, m = 2 * kexists k : nat, S n = 2 * kH: even 1
H0: forall m : nat, m < 1 -> even m -> exists k : nat, m = 2 * kexists k : nat, 1 = 2 * kn: nat
H: even (S (S n))
H0: forall m : nat, m < S (S n) -> even m -> exists k : nat, m = 2 * kexists k : nat, S (S n) = 2 * kinversion H.H: even 1
H0: forall m : nat, m < 1 -> even m -> exists k : nat, m = 2 * kexists k : nat, 1 = 2 * kn: nat
H: even (S (S n))
H0: forall m : nat, m < S (S n) -> even m -> exists k : nat, m = 2 * kexists k : nat, S (S n) = 2 * kn: nat
H: even (S (S n))
H0: forall m : nat, m < S (S n) -> even m -> exists k : nat, m = 2 * k
n0: nat
H2: even n
H1: n0 = nexists k : nat, S (S n) = 2 * kn: nat
H: even (S (S n))
H0: forall m : nat, m < S (S n) -> even m -> exists k : nat, m = 2 * k
H2: even nexists k : nat, S (S n) = 2 * kn: nat
H0: forall m : nat, m < S (S n) -> even m -> exists k : nat, m = 2 * k
H2: even nexists k : nat, S (S n) = 2 * kn: nat
H0: forall m : nat, m < S (S n) -> even m -> exists k : nat, m = 2 * k
H2: even nn < S (S n)n: nat
H0: forall m : nat, m < S (S n) -> even m -> exists k : nat, m = 2 * k
H2: even neven nn: nat
H0: forall m : nat, m < S (S n) -> even m -> exists k : nat, m = 2 * k
H2: even n
x: nat
H: n = 2 * xexists k : nat, S (S n) = 2 * klia.n: nat
H0: forall m : nat, m < S (S n) -> even m -> exists k : nat, m = 2 * k
H2: even nn < S (S n)apply H2.n: nat
H0: forall m : nat, m < S (S n) -> even m -> exists k : nat, m = 2 * k
H2: even neven nn: nat
H0: forall m : nat, m < S (S n) -> even m -> exists k : nat, m = 2 * k
H2: even n
x: nat
H: n = 2 * xexists k : nat, S (S n) = 2 * kx: nat
H2: even (2 * x)
H0: forall m : nat, m < S (S (2 * x)) -> even m -> exists k : nat, m = 2 * kexists k : nat, S (S (2 * x)) = 2 * kx: nat
H2: even (2 * x)
H0: forall m : nat, m < S (S (2 * x)) -> even m -> exists k : nat, m = 2 * kS (S (2 * x)) = 2 * S xlia. Qed.x: nat
H2: even (2 * x)
H0: forall m : nat, m < S (S (2 * x)) -> even m -> exists k : nat, m = 2 * kS (S (x + (x + 0))) = S (x + S (x + 0))
There is a much better way to prove this theorem: induction on even n!
n: nateven n -> exists k : nat, n = 2 * kn: nateven n -> exists k : nat, n = 2 * kn: nat
H: even nexists k : nat, n = 2 * kexists k : nat, 0 = 2 * kn: nat
H: even n
IHeven: exists k : nat, n = 2 * kexists k : nat, S (S n) = 2 * kexists k : nat, 0 = 2 * kreflexivity.0 = 2 * 0n: nat
H: even n
IHeven: exists k : nat, n = 2 * kexists k : nat, S (S n) = 2 * kn: nat
H: even n
x: nat
H0: n = 2 * xexists k : nat, S (S n) = 2 * kx: nat
H: even (2 * x)exists k : nat, S (S (2 * x)) = 2 * klia. Qed.x: nat
H: even (2 * x)S (S (2 * x)) = 2 * S x
Just like we can define the connectives without Inductives,
by only using forall and implication, we can also define inductive
relations without using Inductive. 
The above exists k, n = 2 * k is an example of of that, but there 
is a systematic way to do this.
We first define a higher-order predicate supereven P that says 
that P is a superset of the even numbers:
Definition supereven P := P 0 /\ forall m, P m -> P (S (S m)).That is, a predicate P is a superset of the even numbers, if
P 0holds- if
P mholds, thenP (S (S m))holds
Note that these two conjuncts correspond exactly to the two clauses
in the Inductive definition of even.
We can now define the even' predicate as the intersection of all 
supersets of even numbers.
Definition even' n := forall p, supereven p -> p n.We can now prove that even' is equivalent to even.
n: nateven' n <-> even nn: nateven' n <-> even nn: nateven' n -> even nn: nateven n -> even' nn: nateven' n -> even nn: nat
H: even' neven nn: nat
H: even' nsupereven (fun n : nat => even n)n: nat
H: even' neven 0 /\ (forall m : nat, even m -> even (S (S m)))n: nat
H: even' neven 0n: nat
H: even' nforall m : nat, even m -> even (S (S m))apply even_0.n: nat
H: even' neven 0n: nat
H: even' nforall m : nat, even m -> even (S (S m))n: nat
H: even' n
m: nat
Hm: even meven (S (S m))apply Hm.n: nat
H: even' n
m: nat
Hm: even meven mn: nateven n -> even' nn: nat
H: even neven' neven' 0n: nat
H: even n
IHeven: even' neven' (S (S n))even' 0forall p : nat -> Prop, supereven p -> p 0p: nat -> Prop
Hp: supereven pp 0p: nat -> Prop
Hp: p 0 /\ (forall m : nat, p m -> p (S (S m)))p 0apply H.p: nat -> Prop
H: p 0
H0: forall m : nat, p m -> p (S (S m))p 0n: nat
H: even n
IHeven: even' neven' (S (S n))n: nat
H: even n
IHeven: forall p : nat -> Prop, supereven p -> p nforall p : nat -> Prop, supereven p -> p (S (S n))n: nat
H: even n
IHeven: forall p : nat -> Prop, supereven p -> p n
p: nat -> Prop
Hp: supereven pp (S (S n))n: nat
H: even n
IHeven: forall p : nat -> Prop, supereven p -> p n
p: nat -> Prop
Hp: supereven psupereven (fun n : nat => p (S (S n)))n: nat
H: even n
IHeven: forall p : nat -> Prop, p 0 /\ (forall m : nat, p m -> p (S (S m))) -> p n
p: nat -> Prop
Hp: p 0 /\ (forall m : nat, p m -> p (S (S m)))p 2 /\ (forall m : nat, p (S (S m)) -> p (S (S (S (S m)))))n: nat
H: even n
IHeven: forall p : nat -> Prop, p 0 /\ (forall m : nat, p m -> p (S (S m))) -> p n
p: nat -> Prop
H0: p 0
H1: forall m : nat, p m -> p (S (S m))p 2 /\ (forall m : nat, p (S (S m)) -> p (S (S (S (S m)))))n: nat
H: even n
IHeven: forall p : nat -> Prop, p 0 /\ (forall m : nat, p m -> p (S (S m))) -> p n
p: nat -> Prop
H0: p 0
H1: forall m : nat, p m -> p (S (S m))p 2n: nat
H: even n
IHeven: forall p : nat -> Prop, p 0 /\ (forall m : nat, p m -> p (S (S m))) -> p n
p: nat -> Prop
H0: p 0
H1: forall m : nat, p m -> p (S (S m))forall m : nat, p (S (S m)) -> p (S (S (S (S m))))n: nat
H: even n
IHeven: forall p : nat -> Prop, p 0 /\ (forall m : nat, p m -> p (S (S m))) -> p n
p: nat -> Prop
H0: p 0
H1: forall m : nat, p m -> p (S (S m))p 2apply H0.n: nat
H: even n
IHeven: forall p : nat -> Prop, p 0 /\ (forall m : nat, p m -> p (S (S m))) -> p n
p: nat -> Prop
H0: p 0
H1: forall m : nat, p m -> p (S (S m))p 0n: nat
H: even n
IHeven: forall p : nat -> Prop, p 0 /\ (forall m : nat, p m -> p (S (S m))) -> p n
p: nat -> Prop
H0: p 0
H1: forall m : nat, p m -> p (S (S m))forall m : nat, p (S (S m)) -> p (S (S (S (S m))))n: nat
H: even n
IHeven: forall p : nat -> Prop, p 0 /\ (forall m : nat, p m -> p (S (S m))) -> p n
p: nat -> Prop
H0: p 0
H1: forall m : nat, p m -> p (S (S m))
m: nat
Hm: p (S (S m))p (S (S (S (S m))))apply Hm. Qed.n: nat
H: even n
IHeven: forall p : nat -> Prop, p 0 /\ (forall m : nat, p m -> p (S (S m))) -> p n
p: nat -> Prop
H0: p 0
H1: forall m : nat, p m -> p (S (S m))
m: nat
Hm: p (S (S m))p (S (S m))