(** * Software Foundations, Formally Benjamin C. Pierce Version of 10/29/2007 *) Require Export lec13_sol. (* ====================================================================== *) (* LECTURE 14 *) (* ====================================================================== *) (* More on programming in the lambda-calculus *) Module LambdaContd. Export Lambda. Module LambdaExamplesAgain. (* Since last week, I've found some better ways of using Coq's features to help illustrate example evaluation sequences (and tweaked some things to help with the way Coq displays lambda-terms). So let's start over from the beginning with programming in the lambda-calculus... *) (* To make the notation in the examples as close as possible to TAPL, let's introduce some more names for variables. Coq will do a better job with printing if we choose numbers that do not already have names (like [zero], [one], [two]), so let's choose larger numbers to represent variables in lambda-terms. (This looks hideous, but all we're doing is choosing 26 different numbers to act as names in the examples.) *) Notation a := (S (S (S (S (S (S (S (S (S (S (S (S (S O))))))))))))). Notation b := (S (S (S (S (S (S (S (S (S (S (S (S (S (S O)))))))))))))). Notation c := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O))))))))))))))). Notation d := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O)))))))))))))))). Notation e := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O))))))))))))))))). Notation f := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O)))))))))))))))))). Notation g := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O))))))))))))))))))). Notation h := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O)))))))))))))))))))). Notation i := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O))))))))))))))))))))). Notation j := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O)))))))))))))))))))))). Notation k := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O))))))))))))))))))))))). Notation l := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O)))))))))))))))))))))))). Notation m := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O))))))))))))))))))))))))). Notation n := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O)))))))))))))))))))))))))). Notation o := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O))))))))))))))))))))))))))). Notation p := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O)))))))))))))))))))))))))))). Notation q := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O))))))))))))))))))))))))))))). Notation r := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O)))))))))))))))))))))))))))))). Notation s := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O))))))))))))))))))))))))))))))). Notation t := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O)))))))))))))))))))))))))))))))). Notation u := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O))))))))))))))))))))))))))))))))). Notation v := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O)))))))))))))))))))))))))))))))))). Notation w := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O))))))))))))))))))))))))))))))))))). Notation x := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O)))))))))))))))))))))))))))))))))))). Notation y := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O))))))))))))))))))))))))))))))))))))). Notation z := (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S (S O)))))))))))))))))))))))))))))))))))))). (* LATER: Would it work better to define enough number abbreviations in the first lecture?! (And maybe this is reason enough to write them c1, c2, etc, instead of one, two...) *) (* ---------------------------------------------------------------------- *) (* "Animation" of evaluation sequences *) (* A little bit of Coq hacking gives us a means to "animate" sequences of evaluation steps. The details of these definitions are not important (and they use some Coq features that we have not seen). The high-level picture is: - [t --> t'] is a proposition asserting that [t] evaluates to [t'] in a single step. - [step] is a tactic that can be used to prove such assertions automatically. - [t -->* t'] is a proposition asserting that [t] evaluates to [t'] in some number of steps. - [steps] is a tactic that can be used to prove such assertions automatically. *) Inductive simplify_steps : tm -> tm -> Prop := | ss_refl : forall t, simplify_steps t t | ss_step : forall t t' t'', simplify_step t = Some _ t' (* defined in lec13 *) -> simplify_steps t' t'' -> simplify_steps t t''. Hint Constructors simplify_steps. Notation " t --> t' " := (simplify_steps t t') (at level 80). (* This was defined in terms a function [normalize] in lec13, while it's defined in terms of a relation here *) Notation " t -->* t' " := (simplify_steps t t') (at level 80). (* Wei: Extract the real value from the option *) Definition simplify_step' (t:option tm) : tm := match t with | Some t' => t' (* simplify_step will always evaluate to Some when we call this function, so we just give an arbitrary bad value *) | None => AA end. (* Wei: At first I thought the slowness in later proofs is caused by [compute]. Replacing it with [vm_compute] failed because it didn't like [eapply]: "Anomaly: the kernel does not support existential variables. Please report." *) Ltac ss_search_step := (apply ss_refl) || (eapply ss_step; [compute; reflexivity | idtac]). (* The new tactic is based on the insight that we can figure out what to apply with by taking the result of (simplify_step t) when proving (t-->t'). However, this new tactic is even slower (probably due to the complexity of matching goal), so how do we speed up? Ltac ss_search_step := (* Wei: [ss_refl] is applied first because we could have a goal like t -->* t, where t is not normalized. If we reduced t, we'd never be able to prove this goal, unless we reduce the rhs as well. *) (apply ss_refl) || (match goal with | |- (?t --> _) => apply ss_step with (t' := simplify_step' (simplify_step t)) end; [vm_compute; reflexivity | idtac]). *) (* Wei: Why two searches are needed in one step: The first search eapplies ss_step, and the second applies ss_refl *) Ltac step := ss_search_step; ss_search_step. Ltac steps := repeat ss_search_step. (* Wei: Although [name] is defined as [nat], the coercion [name_in_tm] defined in lec13 only applies to [name], not [nat], but here [a..z] will be typed [nat], so we add one more coercion *) Definition nat_in_tm : nat -> tm := tm_var. Coercion nat_in_tm : nat >-> tm. Print Coercions. Lemma check_step : (\x, \y, x @ y) @ AA @ BB --> (\y, AA @ y) @ BB. (* This is an explicit example showing how the previously defined step/steps tactics work *) match goal with | |- (?t --> ?t') => apply ss_step with (t' := simplify_step' (simplify_step t)) end; vm_compute. reflexivity. apply ss_refl. (* Proof. step. *) Qed. Lemma check_steps : (\x, \y, x @ y) @ AA @ BB -->* AA @ BB. Proof. steps. Qed. (* ---------------------------------------------------------------------- *) (* Church booleans *) (* The boolean [tru] is represented as a function that takes two arguments and returns the first; [fls] is a function that takes two arguments and returns the second. *) Notation tru := (\t, \f, t). Notation fls := (\t, \f, f). (* For example, if we apply [tru] to the constants [AA] and [BB], the result after two steps of beta-reduction is [AA]: *) Lemma check_tru_1 : tru @ AA @ BB = (\t, \f, t) @ AA @ BB. Proof. reflexivity. Qed. Lemma check_tru_2 : (\t, \f, t) @ AA @ BB --> (\f, AA) @ BB. Proof. step. Qed. Lemma check_tru_3 : (\f, AA) @ BB --> AA. Proof. step. Qed. (* Similarly: *) Lemma check_fls : fls @ AA @ BB -->* BB. Proof. steps. Qed. (* The lambda-term [bnot] takes a lambda-term [b] representing a boolean and yields another term representing the negation of this boolean. *) Notation bnot := (\b, b @ fls @ tru). Lemma check_bnot_0 : ((bnot @ tru) @ AA @ BB) = (((\b, b @ fls @ tru) @ tru) @ AA @ BB). Proof. reflexivity. Qed. Lemma check_bnot_1 : (((\b, b @ fls @ tru) @ tru) @ AA @ BB) --> ((tru @ fls @ tru) @ AA @ BB). Proof. step. Qed. Lemma check_bnot_2 : ((tru @ fls @ tru) @ AA @ BB) -->* (fls @ AA @ BB). Proof. steps. Qed. Lemma check_bnot_3 : (fls @ AA @ BB) -->* BB. Proof. steps. Qed. (* Similarly, [and] takes two arguments representing booleans and yields a lambda-term representing their logical conjunction. *) Notation and := (\b, \c, b @ c @ fls). Lemma check_and1 : ((and @ tru @ tru) @ AA @ BB) -->* AA. Proof. steps. Qed. Lemma check_and2 : ((and @ tru @ fls) @ AA @ BB) -->* BB. Proof. steps. Qed. Lemma check_and3 : ((and @ fls @ tru) @ AA @ BB) -->* BB. Proof. steps. Qed. Lemma check_and4 : ((and @ fls @ fls) @ AA @ BB) -->* BB. Proof. steps. Qed. (* OPTIONAL EXERCISE: Write out the detailed steps of the evaluation sequence for [check_and2] in the same style as we did above for [check_bnot]. *) (* ---------------------------------------------------------------------- *) (* Pairs *) (* Using booleans, we can encode pairs of values as lambda-terms. *) Notation pair := (\f, \s, (\b, b @ f @ s)). Notation fst := (\p, p @ tru). Notation snd := (\p, p @ fls). Lemma check_pair1 : (fst @ (pair @ AA @ BB)) -->* AA. Proof. steps. Qed. Lemma check_pair2 : (snd @ (pair @ AA @ BB)) -->* BB. Proof. steps. Qed. (* EXERCISE: Re-write [check_pair1] more explicitly as a series of single evaluation steps -- i.e., using only [-->] and [step] rather than [-->*] and [steps]. *) (* FILL IN HERE *) (* ---------------------------------------------------------------------- *) (* Church numerals *) (* Representing numbers as lambda-terms is also not too hard... *) Notation c_zero := (\s, \z, z). Notation c_one := (\s, \z, s @ z). Notation c_two := (\s, \z, s @ (s @ z)). Notation c_three := (\s, \z, s @ (s @ (s @ z))). Lemma check_three : (c_three @ AA @ BB) -->* AA @ (AA @ (AA @ BB)). Proof. steps. Qed. (* Successor *) Notation scc := (\n, \s, \z, s @ (n @ s @ z)). Lemma check_scc : ((scc @ (scc @ c_one)) @ AA @ BB) -->* AA @ (AA @ (AA @ BB)). Proof. steps. Qed. (* Addition *) Notation pls := (\m, \n, \s, \z, m @ s @ (n @ s @ z)). Lemma check_pls : ((pls @ c_one @ c_two) @ AA @ BB) -->* AA @ (AA @ (AA @ BB)). Proof. steps. Qed. (* Multiplication *) Notation tms := (\m, \n, m @ (pls @ n) @ c_zero). Lemma check_tms : ((tms @ c_two @ c_two) @ AA @ BB) -->* AA @ (AA @ (AA @ (AA @ BB))). Proof. Time steps. Time Qed. (* EXERCISE: Write out [check_tms] in more detail. *) Lemma check_tms_1 : (tms @ c_two @ c_two) @ AA @ BB -->* c_two @ (pls @ c_two) @ c_zero @ AA @ BB. Proof. steps. Qed. Lemma check_tms_2 : c_two @ (pls @ c_two) @ c_zero @ AA @ BB -->* c_two @ (\n, \s, \z, c_two @ s @ (n @ s @ z)) @ c_zero @ AA @ BB. Proof. steps. Qed. Lemma check_tms_3 : c_two @ (\n, \s, \z, c_two @ s @ (n @ s @ z)) @ c_zero @ AA @ BB -->* (\n, \s, \z, c_two @ s @ (n @ s @ z)) @ ((\n, \s, \z, c_two @ s @ (n @ s @ z)) @ c_zero) @ AA @ BB. Proof. steps. Qed. Lemma check_tms_4 : (\n, \s, \z, c_two @ s @ (n @ s @ z)) @ ((\n, \s, \z, c_two @ s @ (n @ s @ z)) @ c_zero) @ AA @ BB -->* (\n, \s, \z, c_two @ s @ (n @ s @ z)) @ (\s, \z, c_two @ s @ (c_zero @ s @ z)) @ AA @ BB. Proof. steps. Qed. Lemma check_tms_5 : (\n, \s, \z, c_two @ s @ (n @ s @ z)) @ (\s, \z, c_two @ s @ (c_zero @ s @ z)) @ AA @ BB -->* (\s, \z, c_two @ s @ ((\s, \z, c_two @ s @ (c_zero @ s @ z)) @ s @ z)) @ AA @ BB. Proof. steps. Qed. Lemma check_tms_6 : (\s, \z, c_two @ s @ ((\s, \z, c_two @ s @ (c_zero @ s @ z)) @ s @ z)) @ AA @ BB -->* c_two @ AA @ ((\s, \z, c_two @ s @ (c_zero @ s @ z)) @ AA @ BB). Proof. steps. Qed. Lemma check_tms_7 : c_two @ AA @ ((\s, \z, c_two @ s @ (c_zero @ s @ z)) @ AA @ BB) -->* (\z, AA @ (AA @ z)) @ ((\s, \z, c_two @ s @ (c_zero @ s @ z)) @ AA @ BB). Proof. steps. Qed. Lemma check_tms_8 : (\z, AA @ (AA @ z)) @ ((\s, \z, c_two @ s @ (c_zero @ s @ z)) @ AA @ BB) -->* (\z, AA @ (AA @ z)) @ (c_two @ AA @ (c_zero @ AA @ BB)). Proof. steps. Qed. Lemma check_tms_9 : (\z, AA @ (AA @ z)) @ (c_two @ AA @ (c_zero @ AA @ BB)) -->* (\z, AA @ (AA @ z)) @ (AA @ (AA @ BB)). Proof. steps. Qed. Lemma check_tms_10 : (\z, AA @ (AA @ z)) @ (AA @ (AA @ BB)) -->* AA @ (AA @ (AA @ (AA @ BB))). Proof. steps. Qed. (* Zero test *) Notation iszro := (\m, m @ (\x, fls) @ tru). (* EXERCISE: Write out an evaluation sequence showing that iszro @ c_two @ AA @ BB -->* BB. Use your own judgment to decide how may intermediate terms to include. *) (* FILL IN HERE *) (* ---------------------------------------------------------------------- *) (* Predecessor *) (* [zz] is the pair (c_zero,c_zero) *) Notation zz := (pair @ c_zero @ c_zero). (* [ss] is a function that takes a pair (m,n) and yields the pair (n,n+1) *) Notation ss := (\p, pair @ (snd @ p) @ (pls @ c_one @ (snd @ p))). (* Now the predecessor function takes a number [m], applies [ss] to [zz], [m] times, to produce the pair (m-1,m), and then returns the first component of this pair. *) Notation prd := (\m, fst @ (m @ ss @ zz)). (* EXERCISE: Write a series of lemmas in the style of [check_bnot_0] through [check_bnot_3] above and [check_fact0] through [check_fact14] below, demonstrating that (prd @ c_two) @ AA @ BB -->* AA @ BB. (You have some freedom in the choice of how many steps at a time to reduce. Choose a sequence of at least five intermediate terms that make sense to you.) *) (* FILL IN HERE *) (* ---------------------------------------------------------------------- *) (* Divergence *) Notation omega := ((\x, x @ x) @ (\x, x @ x)). Lemma check_omega : omega --> omega. Proof. step. Qed. Lemma omega_not_normalizing : forall n, normalize omega n = None _. Proof. intros n0. induction n0. CASE "O". reflexivity. CASE "S". simpl. assumption. Qed. (* ---------------------------------------------------------------------- *) (* Thunks *) (* Putting a dummy lambda in front of a divergent (or just expensive) computation "delays" the computation. This operation is sometimes called "thunking." A lambda-abstraction that throws away its argument (i.e., whose only purpose is to delay evaluation of the body) is called a THUNK. *) Notation poisonpill := (\y, omega). (* [poisonpill] is a thunk that, when evaluated, will diverge. But we can do all sorts of other things with it: pass it as an argument to another function, put it in a pair, extract it again, etc. *) Lemma check_pp1 : (\p, fst @ (pair @ p @ AA) @ BB) @ poisonpill --> fst @ (pair @ poisonpill @ AA) @ BB. Proof. step. Qed. Lemma check_pp2 : fst @ (pair @ poisonpill @ AA) @ BB --> fst @ ((\s, \b, b @ poisonpill @ s) @ AA) @ BB. Proof. step. Qed. Lemma check_pp3 : fst @ ((\s, \b, b @ poisonpill @ s) @ AA) @ BB --> fst @ (\b, b @ poisonpill @ AA) @ BB. Proof. step. Qed. Lemma check_pp4 : fst @ (\b, b @ poisonpill @ AA) @ BB --> (\b, b @ poisonpill @ AA) @ tru @ BB. Proof. step. Qed. Lemma check_pp5 : (\b, b @ poisonpill @ AA) @ tru @ BB --> tru @ poisonpill @ AA @ BB. Proof. step. Qed. Lemma check_pp6 : tru @ poisonpill @ AA @ BB --> (\f, poisonpill) @ AA @ BB. Proof. step. Qed. Lemma check_pp7 : (\f, poisonpill) @ AA @ BB --> poisonpill @ BB. Proof. step. Qed. Lemma check_pp8 : poisonpill @ BB --> omega. Proof. step. Qed. Lemma check_pp9 : omega --> omega. Proof. step. Qed. (* ---------------------------------------------------------------------- *) (* Conditional *) (* We can create a "safe conditional" by thunking both branches, doing the test, and then applying the result to a dummy argument to continue evaluation. *) Notation test := (\b, \t, \f, b @ t @ f @ (\x,x)). Lemma check_test : test @ tru @ (\x, c_zero) @ (\x, omega) -->* c_zero. Proof. steps. Qed. (* ---------------------------------------------------------------------- *) (* Recursion *) (* See TAPL for explanations of the following... *) (* Wei: Yf can be seen as the generic Y combinator instantiated with FF, ie Yf=Y FF *) Notation Yf := ((\x, FF @ (x @ x)) @ (\x, FF @ (x @ x))). (* Yf -> f Yf *) Lemma check_Yf1 : ((\x, FF @ (x @ x)) @ (\x, FF @ (x @ x))) --> FF @ ((\x, FF @ (x @ x)) @ (\x, FF @ (x @ x))). Proof. steps. Qed. (* Wei: The next evaluation step shows that Y only works in a call-by-name setting! With call-by value, f Yf -> f (f Yf) -> ... We need to delay Yf in f Yf, hence called the Z combinator See TAPL and http://ttic.uchicago.edu/~umut/classes/CMSC321-Fall05/lectures/lec5.pdf *) Lemma check_Yf2 : FF @ ((\x, FF @ (x @ x)) @ (\x, FF @ (x @ x))) --> FF @ (FF @ ((\x, FF @ (x @ x)) @ (\x, FF @ (x @ x)))). Proof. steps. Qed. Notation omegav := (\y, (\x, (\y, x @ x @ y)) @ (\x, (\y, x @ x @ y)) @ y). Lemma check_ov0 : omegav @ AA = (\y, (\x, (\y, x @ x @ y)) @ (\x, (\y, x @ x @ y)) @ y) @ AA. Proof. reflexivity. Qed. Lemma check_ov1 : (\y, (\x, (\y, x @ x @ y)) @ (\x, (\y, x @ x @ y)) @ y) @ AA --> (\x, (\y, x @ x @ y)) @ (\x, (\y, x @ x @ y)) @ AA. Proof. steps. Qed. Lemma check_ov2 : (\x, (\y, x @ x @ y)) @ (\x, (\y, x @ x @ y)) @ AA --> (\y, (\x, (\y, x @ x @ y)) @ (\x, (\y, x @ x @ y)) @ y) @ AA. Proof. steps. Qed. Lemma check_ov3 : (\y, (\x, (\y, x @ x @ y)) @ (\x, (\y, x @ x @ y)) @ y) @ AA = omegav @ AA. Proof. reflexivity. Qed. Notation Z_FF := (\y, (\x, FF @ (\y, x @ x @ y)) @ (\x, FF @ (\y, x @ x @ y)) @ y). Lemma check_Z_FF0 : Z_FF @ AA = (\y, (\x, FF @ (\y, x @ x @ y)) @ (\x, FF @ (\y, x @ x @ y)) @ y) @ AA. Proof. reflexivity. Qed. Lemma check_Z_FF1 : (\y, (\x, FF @ (\y, x @ x @ y)) @ (\x, FF @ (\y, x @ x @ y)) @ y) @ AA --> (\x, FF @ (\y, x @ x @ y)) @ (\x, FF @ (\y, x @ x @ y)) @ AA. Proof. steps. Qed. Lemma check_Z_FF2 : (\x, FF @ (\y, x @ x @ y)) @ (\x, FF @ (\y, x @ x @ y)) @ AA --> FF @ (\y, (\x, FF @ (\y, x @ x @ y)) @ (\x, FF @ (\y, x @ x @ y)) @ y) @ AA. Proof. steps. Qed. Lemma check_Z_FF3 : FF @ (\y, (\x, FF @ (\y, x @ x @ y)) @ (\x, FF @ (\y, x @ x @ y)) @ y) @ AA = FF @ Z_FF @ AA. Proof. reflexivity. Qed. (* Z f = f (\y, Z f) Y f = f (Y f) *) Notation Z := (\f, (\y, (\x, f @ (\y, x @ x @ y)) @ (\x, f @ (\y, x @ x @ y)) @ y)). Notation f_fact := (\f, \n, test (* if-then-else *) @ (iszro @ n) @ (\z, c_one) @ (\z, tms @ n @ (f @ (prd @ n)))). Notation fact := (Z @ f_fact). Notation Z_fact := (\y, (\x, f_fact @ (\y, x @ x @ y)) @ (\x, f_fact @ (\y, x @ x @ y)) @ y). Lemma check_fact0 : fact @ c_one @ AA @ BB = Z @ f_fact @ c_one @ AA @ BB. Proof. reflexivity. Qed. Lemma check_fact1 : Z @ f_fact @ c_one @ AA @ BB -->* Z_fact @ c_one @ AA @ BB. Proof. Time steps. Time Qed. Lemma check_fact2 : Z_fact @ c_one @ AA @ BB -->* f_fact @ Z_fact @ c_one @ AA @ BB. Proof. Time steps. Time Qed. Lemma check_fact3 : f_fact @ Z_fact @ c_one @ AA @ BB -->* test @ (iszro @ c_one) @ (\z, c_one) @ (\z, tms @ c_one @ (Z_fact @ (prd @ c_one))) @ AA @ BB. Proof. steps. Qed. Lemma check_fact4 : test @ (iszro @ c_one) @ (\z, c_one) @ (\z, tms @ c_one @ (Z_fact @ (prd @ c_one))) @ AA @ BB -->* test @ fls @ (\z, c_one) @ (\z, tms @ c_one @ (Z_fact @ (prd @ c_one))) @ AA @ BB. Proof. steps. Qed. Lemma check_fact5 : test @ fls @ (\z, c_one) @ (\z, tms @ c_one @ (Z_fact @ (prd @ c_one))) @ AA @ BB -->* tms @ c_one @ (Z_fact @ (prd @ c_one)) @ AA @ BB. Proof. steps. Qed. Lemma check_fact6 : tms @ c_one @ (Z_fact @ (prd @ c_one)) @ AA @ BB = (\m, \n, m @ (pls @ n) @ c_zero) @ c_one @ (Z_fact @ (prd @ c_one)) @ AA @ BB. Proof. reflexivity. Qed. Lemma check_fact7 : (\m, \n, m @ (pls @ n) @ c_zero) @ c_one @ (Z_fact @ (prd @ c_one)) @ AA @ BB -->* (\n, c_one @ (pls @ n) @ c_zero) @ (Z_fact @ (prd @ c_one)) @ AA @ BB. Proof. steps. Qed. Lemma check_fact8 : (\n, c_one @ (pls @ n) @ c_zero) @ (Z_fact @ (prd @ c_one)) @ AA @ BB -->* (\n, c_one @ (pls @ n) @ c_zero) @ (Z_fact @ c_zero) @ AA @ BB. Proof. steps. Qed. Lemma check_fact9 : (\n, c_one @ (pls @ n) @ c_zero) @ (Z_fact @ c_zero) @ AA @ BB -->* (\n, c_one @ (pls @ n) @ c_zero) @ (f_fact @ Z_fact @ c_zero) @ AA @ BB. Proof. steps. Qed. Lemma check_fact10 : (\n, c_one @ (pls @ n) @ c_zero) @ (f_fact @ Z_fact @ c_zero) @ AA @ BB -->* (\n, c_one @ (pls @ n) @ c_zero) @ (test @ (iszro @ c_zero) @ (\z, c_one) @ (\z, tms @ c_zero @ (Z_fact @ (prd @ c_zero)))) @ AA @ BB. Proof. steps. Qed. Lemma check_fact11 : (\n, c_one @ (pls @ n) @ c_zero) @ (test @ (iszro @ c_zero) @ (\z, c_one) @ (\z, tms @ c_zero @ (Z_fact @ (prd @ c_zero)))) @ AA @ BB -->* (\n, c_one @ (pls @ n) @ c_zero) @ (test @ tru @ (\z, c_one) @ (\z, tms @ c_zero @ (Z_fact @ (prd @ c_zero)))) @ AA @ BB. Proof. steps. Qed. Lemma check_fact12 : (\n, c_one @ (pls @ n) @ c_zero) @ (test @ tru @ (\z, c_one) @ (\z, tms @ c_zero @ (Z_fact @ (prd @ c_zero)))) @ AA @ BB -->* (\n, c_one @ (pls @ n) @ c_zero) @ c_one @ AA @ BB. Proof. steps. Qed. Lemma check_fact13 : (\n, c_one @ (pls @ n) @ c_zero) @ c_one @ AA @ BB -->* c_one @ (pls @ c_one) @ c_zero @ AA @ BB. Proof. steps. Qed. Lemma check_fact14 : c_one @ (pls @ c_one) @ c_zero @ AA @ BB -->* AA @ BB. Proof. steps. Qed. End LambdaExamplesAgain. End LambdaContd.