Exercise session 2 — Part 1

🏠 Go back to the course homepage.

Interactive Module define_nat started

Inductive types can be defined using the Inductive keyword

  
nat is defined
nat_rect is defined
nat_ind is defined
nat_rec is defined
nat_sind is defined

EXERCISE

Define addition.

  
add is defined
add is recursively defined (guarded on 1st argument)

EXERCISE

Define subtraction on natural numbers, truncating at 0. In other words, when n < m then sub n m = 0.

  
sub is defined
sub is recursively defined (guarded on 1st argument)

EXERCISE

Prove the following lemma. You will replace Admitted with Qed once it is done. What Admitted does should be obvious: it admits a lemma without proof or with a partial proof, it can be used in subsequent proofs as if it were proven.

  

forall n : nat, add n O = n

forall n : nat, add n O = n
n: nat

add n O = n

add O O = O
n: nat
ih: add n O = n
add (S n) O = S n

add O O = O
reflexivity.
n: nat
ih: add n O = n

add (S n) O = S n
n: nat
ih: add n O = n

S (add n O) = S n
n: nat
ih: add n O = n

S n = S n
reflexivity.
add_0 is defined

EXERCISE

  

forall n m : nat, add n (S m) = S (add n m)

forall n m : nat, add n (S m) = S (add n m)
n, m: nat

add n (S m) = S (add n m)
m: nat

add O (S m) = S (add O m)
n, m: nat
ih: add n (S m) = S (add n m)
add (S n) (S m) = S (add (S n) m)
m: nat

add O (S m) = S (add O m)
reflexivity.
n, m: nat
ih: add n (S m) = S (add n m)

add (S n) (S m) = S (add (S n) m)
n, m: nat
ih: add n (S m) = S (add n m)

S (add n (S m)) = S (S (add n m))
n, m: nat
ih: add n (S m) = S (add n m)

S (S (add n m)) = S (S (add n m))
reflexivity.
add_S is defined

With the following commands we declare notations for add and sub.

  Infix "+" := add.
  Infix "-" := sub.

EXERCISE

  

forall n m : nat, n + m - m = n

forall n m : nat, n + m - m = n
n, m: nat

n + m - m = n
n: nat

n + O - O = n
n, m: nat
ih: n + m - m = n
n + S m - S m = n
n: nat

n + O - O = n
n: nat

n - O = n

O - O = O
n: nat
S n - O = S n
all: reflexivity.
n, m: nat
ih: n + m - m = n

n + S m - S m = n
n, m: nat
ih: n + m - m = n

S (n + m) - S m = n
n, m: nat
ih: n + m - m = n

n + m - m = n
assumption.
add_sub is defined

Note the proof can look nicer if we also prove n - O = n.

  

forall n : nat, n - O = n

forall n : nat, n - O = n
n: nat

n - O = n

O - O = O
n: nat
S n - O = S n
all: reflexivity.
sub_O is defined

forall n m : nat, n + m - m = n

forall n m : nat, n + m - m = n
n, m: nat

n + m - m = n
n: nat

n + O - O = n
n, m: nat
ih: n + m - m = n
n + S m - S m = n
n: nat

n + O - O = n
n: nat

n - O = n
apply sub_O.
n, m: nat
ih: n + m - m = n

n + S m - S m = n
n, m: nat
ih: n + m - m = n

S (n + m) - S m = n
n, m: nat
ih: n + m - m = n

n + m - m = n
assumption.
add_sub_alt is defined
Module define_nat is defined

EXERCISE

Define a Boolean predicate deciding equality of natural numbers.

eq_nat is defined
eq_nat is recursively defined (guarded on 1st argument)

EXERCISE


forall n m : nat, eq_nat n m = true <-> n = m

forall n m : nat, eq_nat n m = true <-> n = m
n, m: nat

eq_nat n m = true <-> n = m
m: nat

eq_nat 0 m = true <-> 0 = m
n, m: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m
eq_nat (S n) m = true <-> S n = m
m: nat

eq_nat 0 m = true <-> 0 = m

eq_nat 0 0 = true <-> 0 = 0
m: nat
eq_nat 0 (S m) = true <-> 0 = S m

eq_nat 0 0 = true <-> 0 = 0

true = true <-> 0 = 0

true = true -> 0 = 0

0 = 0 -> true = true
all: reflexivity.
m: nat

eq_nat 0 (S m) = true <-> 0 = S m
m: nat

false = true <-> 0 = S m
m: nat

false = true -> 0 = S m
m: nat
0 = S m -> false = true
all: discriminate.
n, m: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m

eq_nat (S n) m = true <-> S n = m
n: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m

eq_nat (S n) 0 = true <-> S n = 0
n, m: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m
eq_nat (S n) (S m) = true <-> S n = S m
n: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m

eq_nat (S n) 0 = true <-> S n = 0
n: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m

false = true <-> S n = 0
n: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m

false = true -> S n = 0
n: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m
S n = 0 -> false = true
all: discriminate.
n, m: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m

eq_nat (S n) (S m) = true <-> S n = S m
n, m: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m

eq_nat n m = true <-> S n = S m
n, m: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m

eq_nat n m = true -> S n = S m
n, m: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m
S n = S m -> eq_nat n m = true
n, m: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m

eq_nat n m = true -> S n = S m
n, m: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m
h: eq_nat n m = true

S n = S m
n, m: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m
h: eq_nat n m = true

n = m
n, m: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m
h: eq_nat n m = true

eq_nat n m = true
assumption.
n, m: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m

S n = S m -> eq_nat n m = true
n, m: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m
h: S n = S m

eq_nat n m = true
n, m: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m
h: S n = S m

n = m
n, m: nat
ih:= forall m: nat, eq_nat n m = true <-> n = m
h: S n = S m
H0: n = m

m = m
reflexivity.
eq_nat_spec is defined

EXERCISE

cur is defined

EXERCISE

car is defined

Note, we can take a shortcut because there is only one constructor so we have a so-called "irrefutable pattern".

car' is defined

We could also use fst and snd.

car'' is defined

EXERCISE


forall (X Y Z : Type) (f : X * Y -> Z) (p : X * Y), car (cur f) p = f p

forall (X Y Z : Type) (f : X * Y -> Z) (p : X * Y), car (cur f) p = f p
X, Y, Z: Type
f: X * Y -> Z
p: X * Y

car (cur f) p = f p
X, Y, Z: Type
f: X * Y -> Z
x: X
y: Y

car (cur f) (x, y) = f (x, y)
reflexivity.
car_cur is defined

EXERCISE


forall (X Y Z : Type) (f : X -> Y -> Z) (x : X) (y : Y), cur (car f) x y = f x y

forall (X Y Z : Type) (f : X -> Y -> Z) (x : X) (y : Y), cur (car f) x y = f x y

No intros needed, reflexivity does it for us.

  reflexivity.
cur_car is defined

EXERCISE

Definition swap {X Y} (p : X * Y) : Y * X :=

Irrefutable patterns also work with let.

swap is defined

EXERCISE


forall (X Y : Type) (p : X * Y), swap (swap p) = p

forall (X Y : Type) (p : X * Y), swap (swap p) = p
X, Y: Type
p: X * Y

swap (swap p) = p
X, Y: Type
x: X
y: Y

swap (swap (x, y)) = (x, y)
reflexivity.
swap_invol is defined

EXERCISE

Prove true <> false without the tactics inversion or discriminate.

Note: a <> b is a notation for a ≠ b, meaning a = b -> False.


true <> false

true <> false
e: true = false

False
e: true = false

if true then False else True
e: true = false

True
constructor.
true_false is defined
From Stdlib Require Import List. Import ListNotations.

EXERCISE

Prove the following. You will need lemmas, prove them yourself by induction and do not use lemmas from the standard library.


forall (A : Type) (l : list A), l ++ [] = l

forall (A : Type) (l : list A), l ++ [] = l
A: Type
l: list A

l ++ [] = l
A: Type

[] ++ [] = []
A: Type
a: A
l: list A
ih: l ++ [] = l
(a :: l) ++ [] = a :: l
A: Type

[] ++ [] = []
reflexivity.
A: Type
a: A
l: list A
ih: l ++ [] = l

(a :: l) ++ [] = a :: l
A: Type
a: A
l: list A
ih: l ++ [] = l

a :: l ++ [] = a :: l
A: Type
a: A
l: list A
ih: l ++ [] = l

a :: l = a :: l
reflexivity.
app_nil_r is defined

forall (A : Type) (u v w : list A), (u ++ v) ++ w = u ++ v ++ w

forall (A : Type) (u v w : list A), (u ++ v) ++ w = u ++ v ++ w
A: Type
u, v, w: list A

(u ++ v) ++ w = u ++ v ++ w
A: Type
v, w: list A

([] ++ v) ++ w = [] ++ v ++ w
A: Type
a: A
u, v, w: list A
ih: (u ++ v) ++ w = u ++ v ++ w
((a :: u) ++ v) ++ w = (a :: u) ++ v ++ w
A: Type
v, w: list A

([] ++ v) ++ w = [] ++ v ++ w
reflexivity.
A: Type
a: A
u, v, w: list A
ih: (u ++ v) ++ w = u ++ v ++ w

((a :: u) ++ v) ++ w = (a :: u) ++ v ++ w
A: Type
a: A
u, v, w: list A
ih: (u ++ v) ++ w = u ++ v ++ w

a :: (u ++ v) ++ w = a :: u ++ v ++ w
A: Type
a: A
u, v, w: list A
ih: (u ++ v) ++ w = u ++ v ++ w

a :: u ++ v ++ w = a :: u ++ v ++ w
reflexivity.
app_assoc is defined

forall (A : Type) (l1 l2 : list A), rev (l1 ++ l2) = rev l2 ++ rev l1

forall (A : Type) (l1 l2 : list A), rev (l1 ++ l2) = rev l2 ++ rev l1
A: Type
l1, l2: list A

rev (l1 ++ l2) = rev l2 ++ rev l1
A: Type
l2: list A

rev ([] ++ l2) = rev l2 ++ rev []
A: Type
a: A
l1, l2: list A
ih: rev (l1 ++ l2) = rev l2 ++ rev l1
rev ((a :: l1) ++ l2) = rev l2 ++ rev (a :: l1)
A: Type
l2: list A

rev ([] ++ l2) = rev l2 ++ rev []
A: Type
l2: list A

rev l2 = rev l2 ++ []
A: Type
l2: list A

rev l2 = rev l2
reflexivity.
A: Type
a: A
l1, l2: list A
ih: rev (l1 ++ l2) = rev l2 ++ rev l1

rev ((a :: l1) ++ l2) = rev l2 ++ rev (a :: l1)
A: Type
a: A
l1, l2: list A
ih: rev (l1 ++ l2) = rev l2 ++ rev l1

rev (l1 ++ l2) ++ [a] = rev l2 ++ rev l1 ++ [a]
A: Type
a: A
l1, l2: list A
ih: rev (l1 ++ l2) = rev l2 ++ rev l1

(rev l2 ++ rev l1) ++ [a] = rev l2 ++ rev l1 ++ [a]
A: Type
a: A
l1, l2: list A
ih: rev (l1 ++ l2) = rev l2 ++ rev l1

rev l2 ++ rev l1 ++ [a] = rev l2 ++ rev l1 ++ [a]
reflexivity.
rev_app_distr is defined

EXERCISE

X: Type
l: list X

rev (rev l) = l
X: Type
l: list X

rev (rev l) = l
X: Type

rev (rev []) = []
X: Type
x: X
l: list X
ih: rev (rev l) = l
rev (rev (x :: l)) = x :: l
X: Type

rev (rev []) = []
reflexivity.
X: Type
x: X
l: list X
ih: rev (rev l) = l

rev (rev (x :: l)) = x :: l
X: Type
x: X
l: list X
ih: rev (rev l) = l

rev (rev l ++ [x]) = x :: l
X: Type
x: X
l: list X
ih: rev (rev l) = l

rev [x] ++ rev (rev l) = x :: l
X: Type
x: X
l: list X
ih: rev (rev l) = l

rev [x] ++ l = x :: l
X: Type
x: X
l: list X
ih: rev (rev l) = l

x :: l = x :: l
reflexivity.
rev_rev is defined
fast_rev is defined
fast_rev is recursively defined (guarded on 2nd argument)

EXERCISE


forall (A : Type) (l : list A), fast_rev l [] = rev l

forall (A : Type) (l : list A), fast_rev l [] = rev l
A: Type
l: list A

fast_rev l [] = rev l
A: Type
l: list A

forall acc : list A, fast_rev l acc = rev l ++ acc
A: Type
l: list A
h:= forall acc: list A, fast_rev l acc = rev l ++ acc
fast_rev l [] = rev l
A: Type
l: list A

forall acc : list A, fast_rev l acc = rev l ++ acc
A: Type

forall acc : list A, fast_rev [] acc = rev [] ++ acc
A: Type
a: A
l: list A
ih:= forall acc: list A, fast_rev l acc = rev l ++ acc
forall acc : list A, fast_rev (a :: l) acc = rev (a :: l) ++ acc
A: Type

forall acc : list A, fast_rev [] acc = rev [] ++ acc
A: Type
acc: list A

fast_rev [] acc = rev [] ++ acc
A: Type
acc: list A

acc = acc
reflexivity.
A: Type
a: A
l: list A
ih:= forall acc: list A, fast_rev l acc = rev l ++ acc

forall acc : list A, fast_rev (a :: l) acc = rev (a :: l) ++ acc
A: Type
a: A
l: list A
ih:= forall acc: list A, fast_rev l acc = rev l ++ acc
acc: list A

fast_rev (a :: l) acc = rev (a :: l) ++ acc
A: Type
a: A
l: list A
ih:= forall acc: list A, fast_rev l acc = rev l ++ acc
acc: list A

fast_rev l (a :: acc) = (rev l ++ [a]) ++ acc
A: Type
a: A
l: list A
ih:= forall acc: list A, fast_rev l acc = rev l ++ acc
acc: list A

rev l ++ a :: acc = (rev l ++ [a]) ++ acc
A: Type
a: A
l: list A
ih:= forall acc: list A, fast_rev l acc = rev l ++ acc
acc: list A

rev l ++ a :: acc = rev l ++ [a] ++ acc
A: Type
a: A
l: list A
ih:= forall acc: list A, fast_rev l acc = rev l ++ acc
acc: list A

rev l ++ a :: acc = rev l ++ a :: acc
reflexivity.
A: Type
l: list A
h:= forall acc: list A, fast_rev l acc = rev l ++ acc

fast_rev l [] = rev l
A: Type
l: list A
h: fast_rev l [] = rev l ++ []

fast_rev l [] = rev l
A: Type
l: list A
h: fast_rev l [] = rev l

fast_rev l [] = rev l
assumption.
fast_rev_eq is defined

Note we could have done it without the assert using generalize.


forall (A : Type) (l : list A), fast_rev l [] = rev l

forall (A : Type) (l : list A), fast_rev l [] = rev l
A: Type
l: list A

fast_rev l [] = rev l
A: Type
l: list A

fast_rev l [] = rev l ++ []
A: Type
l: list A

forall acc : list A, fast_rev l acc = rev l ++ acc
A: Type

forall acc : list A, fast_rev [] acc = rev [] ++ acc
A: Type
a: A
l: list A
ih:= forall acc: list A, fast_rev l acc = rev l ++ acc
forall acc : list A, fast_rev (a :: l) acc = rev (a :: l) ++ acc
A: Type

forall acc : list A, fast_rev [] acc = rev [] ++ acc
A: Type
acc: list A

fast_rev [] acc = rev [] ++ acc
A: Type
acc: list A

acc = acc
reflexivity.
A: Type
a: A
l: list A
ih:= forall acc: list A, fast_rev l acc = rev l ++ acc

forall acc : list A, fast_rev (a :: l) acc = rev (a :: l) ++ acc
A: Type
a: A
l: list A
ih:= forall acc: list A, fast_rev l acc = rev l ++ acc
acc: list A

fast_rev (a :: l) acc = rev (a :: l) ++ acc
A: Type
a: A
l: list A
ih:= forall acc: list A, fast_rev l acc = rev l ++ acc
acc: list A

fast_rev l (a :: acc) = (rev l ++ [a]) ++ acc
A: Type
a: A
l: list A
ih:= forall acc: list A, fast_rev l acc = rev l ++ acc
acc: list A

rev l ++ a :: acc = (rev l ++ [a]) ++ acc
A: Type
a: A
l: list A
ih:= forall acc: list A, fast_rev l acc = rev l ++ acc
acc: list A

rev l ++ a :: acc = rev l ++ [a] ++ acc
A: Type
a: A
l: list A
ih:= forall acc: list A, fast_rev l acc = rev l ++ acc
acc: list A

rev l ++ a :: acc = rev l ++ a :: acc
reflexivity.
fast_rev_eq_alt is defined