3.8. Exercises
Define each function and prove or state each theorem, replacing sorry. Download the exercise file Lecture03.lean and open it in VS Code. The file already contains the definitions of AExp, eval, appendPretty, and reverse from the lecture.
Exercise 1. Define the predecessor function, with pred 0 = 0.
def pred : ℕ → ℕ := sorry
-- Expected: #eval pred 5 gives 4, #eval pred 0 gives 0.
Exercise 2. Define doubling by recursion, without *, and prove the ground equation by computation.
def double : ℕ → ℕ := sorry
theorem double_five : double 5 = 10 := sorry
Exercise 3. Define the environment that maps "x" to 3, "y" to 17, and every other name to 201, and prove the two evaluations by computation.
def someEnv : String → ℤ := sorry
theorem eval_sub :
eval someEnv
(AExp.sub (AExp.var "y") (AExp.var "x")) = 14 :=
sorry
theorem eval_div_zero :
eval someEnv
(AExp.div (AExp.var "y") (AExp.num 0)) = 0 :=
sorry
Exercise 4. Define the sum of a list of natural numbers, and prove the ground equation by computation.
def sumList : List ℕ → ℕ := sorry
theorem sumList_example : sumList [1, 2, 3] = 6 := sorry
Exercise 5. Define the length of a list, with an implicit type argument, and prove the ground equation by computation.
def length {α : Type} : List α → ℕ := sorry
theorem length_three : length [1, 2, 3] = 3 := sorry
Exercise 6. Define map, which applies a function to every element, then state, with sorry, its two functorial laws. Mapping the identity function changes nothing, and mapping a composition equals composing the maps.
def map {α β : Type} (f : α → β) : List α → List β :=
sorry
-- State the two laws here as theorems proved by sorry:
-- map_ident : mapping (fun x => x) over xs gives xs.
-- map_comp : map g (map f xs) equals mapping their
-- composition over xs.
Exercise 7. Define flatten, which concatenates a list of lists with appendPretty, then state, with sorry, that the length of the result is the sum of the lengths of the inner lists, using length, map and sumList of the exercises above.
def flatten {α : Type} : List (List α) → List α := sorry
-- State flatten_length here as a theorem proved by sorry:
-- length (flatten xss) equals sumList (map length xss).
Exercise 8. Complete simplify, which removes additions of 0, multiplications by 1, and divisions by 1, following the given cases, then state, with sorry, its correctness. Simplifying preserves the value under every environment.
def simplify : AExp → AExp
| AExp.add (AExp.num 0) e₂ => simplify e₂
| AExp.add e₁ (AExp.num 0) => simplify e₁
| AExp.sub e₁ e₂ => sorry
| AExp.mul e₁ e₂ => sorry
| AExp.div e₁ e₂ => sorry
| AExp.add e₁ e₂ =>
AExp.add (simplify e₁) (simplify e₂)
| e => e
-- State simplify_correct here as a theorem proved by
-- sorry: for every env and e, eval env (simplify e)
-- equals eval env e.
Exercise 9. Define the size of an expression, counting every constructor, and its depth, counting the longest constructor chain, then state, with sorry, that the depth never exceeds the size.
def size : AExp → ℕ := sorry
def depth : AExp → ℕ := sorry
theorem depth_le_size (e : AExp) :
depth e ≤ size e := sorry
Exercise 10. Define mirror, which swaps the operands of every addition and multiplication and leaves the rest unchanged, then state, with sorry, that mirroring preserves the value under every environment.
def mirror : AExp → AExp := sorry
-- State mirror_eval here as a theorem proved by sorry.