Formal Software Verification

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 declaration uses `sorry`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 declaration uses `sorry`double : := sorry theorem declaration uses `sorry`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 declaration uses `sorry`someEnv : String := sorry theorem declaration uses `sorry`eval_sub : eval someEnv (AExp.sub (AExp.var "y") (AExp.var "x")) = 14 := sorry theorem declaration uses `sorry`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 declaration uses `sorry`sumList : List := sorry theorem declaration uses `sorry`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 declaration uses `sorry`length {α : Type} : List α := sorry theorem declaration uses `sorry`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 declaration uses `sorry`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 declaration uses `sorry`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 declaration uses `sorry`declaration uses `sorry`declaration uses `sorry`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 declaration uses `sorry`size : AExp := sorry def declaration uses `sorry`depth : AExp := sorry theorem declaration uses `sorry`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 declaration uses `sorry`mirror : AExp AExp := sorry -- State mirror_eval here as a theorem proved by sorry.