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 0
holds- if
P m
holds, 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))