(** * Software Foundations, Formally Benjamin C. Pierce Version of 11/7/2007 Before handing in this file with your homework solutions, please fill in the names of all members of your group: Also, please tell us roughly how many person-hours you spent on this assignment (i.e., if you worked in a group, give us the SUM of the number of hours spent by each person individually). *) Require Export lec1213. (* ====================================================================== *) (* More on programming in the lambda-calculus *) Module LambdaContd. Export Lambda. (* ---------------------------------------------------------------------- *) (* "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' -> simplify_steps t' t'' -> simplify_steps t t''. Hint Constructors simplify_steps. Notation " t --> t' " := (simplify_steps t t') (at level 80). Notation " t -->* t' " := (simplify_steps t t') (at level 80). Ltac ss_search_step := (apply ss_refl) || (eapply ss_step; [compute; reflexivity | idtac]). Ltac step := ss_search_step; ss_search_step. Ltac steps := repeat ss_search_step. (* ---------------------------------------------------------------------- *) 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)))))))))))))))))))))))))))))))))))))). (* COMMENTED OUT TO SAVE COMPILATION TIME... Lemma check_step : (\x, \y, x @ y) @ AA @ BB --> (\y, AA @ y) @ BB. 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). (* COMMENTED OUT TO SAVE COMPILATION TIME... (* 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). (* COMMENTED OUT TO SAVE COMPILATION TIME... 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). (* COMMENTED OUT TO SAVE COMPILATION TIME... 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]. *) (* SOLUTION *) (* COMMENTED OUT TO SAVE COMPILATION TIME... Lemma check_pair1_1 : (fst @ (pair @ AA @ BB)) --> (fst @ ((\s, \b, b @ AA @ s) @ BB)). Proof. step. Qed. Lemma check_pair1_2 : (fst @ ((\s, \b, b @ AA @ s) @ BB)) --> (fst @ (\b, b @ AA @ BB)). Proof. step. Qed. Lemma check_pair1_3 : (fst @ (\b, b @ AA @ BB)) --> (\b, b @ AA @ BB) @ tru. Proof. step. Qed. Lemma check_pair1_4 : (\b, b @ AA @ BB) @ tru --> tru @ AA @ BB. Proof. step. Qed. Lemma check_pair1_5 : tru @ AA @ BB --> (\f, AA) @ BB. Proof. step. Qed. Lemma check_pair1_6 : (\f, AA) @ BB --> AA. Proof. step. Qed. *) (* ---------------------------------------------------------------------- *) (* 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)). (* COMMENTED OUT TO SAVE COMPILATION TIME... 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)). (* COMMENTED OUT TO SAVE COMPILATION TIME... 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). (* COMMENTED OUT TO SAVE COMPILATION TIME... Lemma check_tms : ((tms @ c_two @ c_two) @ AA @ BB) -->* AA @ (AA @ (AA @ (AA @ BB))). Proof. steps. Qed. *) (* EXERCISE: Write out [check_tms] in more detail. *) (* SOLUTION *) (* COMMENTED OUT TO SAVE COMPILATION TIME... 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 many intermediate terms to include. *) (* SOLUTION *) (* Solution still needs to be written *) (* ---------------------------------------------------------------------- *) (* 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.) *) (* SOLUTION *) (* COMMENTED OUT TO SAVE COMPILATION TIME... Lemma check_prd_1 : (prd @ c_two) @ AA @ BB = ((\m, fst @ (m @ ss @ zz)) @ c_two) @ AA @ BB. Proof. reflexivity. Qed. Lemma check_prd_2 : (\m, fst @ (m @ ss @ zz)) @ c_two @ AA @ BB --> fst @ (c_two @ ss @ zz) @ AA @ BB. Proof. step. Qed. Lemma check_prd_3 : fst @ (c_two @ ss @ zz) @ AA @ BB -->* fst @ ((\z, ss @ (ss @ z)) @ zz) @ AA @ BB. Proof. steps. Qed. Lemma check_prd_4 : fst @ ((\z, ss @ (ss @ z)) @ zz) @ AA @ BB -->* fst @ ((\z, ss @ (ss @ z)) @ (\b, b @ c_zero @ c_zero)) @ AA @ BB. Proof. steps. Qed. Lemma check_prd_5 : fst @ ((\z, ss @ (ss @ z)) @ (\b, b @ c_zero @ c_zero)) @ AA @ BB -->* fst @ (ss @ (ss @ (\b, b @ c_zero @ c_zero))) @ AA @ BB. Proof. steps. Qed. Lemma check_prd_6 : fst @ ((\z, ss @ (ss @ z)) @ (\b, b @ c_zero @ c_zero)) @ AA @ BB -->* fst @ (ss @ (pair @ (snd @ (\b, b @ c_zero @ c_zero)) @ (pls @ c_one @ (snd @ (\b, b @ c_zero @ c_zero))))) @ AA @ BB. Proof. steps. Qed. Lemma check_prd_7 : fst @ (ss @ (pair @ (snd @ (\b, b @ c_zero @ c_zero)) @ (pls @ c_one @ (snd @ (\b, b @ c_zero @ c_zero))))) @ AA @ BB -->* fst @ (ss @ (pair @ c_zero @ ((\m, \n, \s, \z, m @ s @ (n @ s @ z)) @ c_one @ (snd @ (\b, b @ c_zero @ c_zero))))) @ AA @ BB. Proof. steps. Qed. Lemma check_prd_8 : fst @ (ss @ (pair @ c_zero @ (pls @ c_one @ (snd @ (\b, b @ c_zero @ c_zero))))) @ AA @ BB -->* fst @ (ss @ ((\s, \b, b @ c_zero @ s) @ (pls @ c_one @ (snd @ (\b, b @ c_zero @ c_zero))))) @ AA @ BB. Proof. steps. Qed. Lemma check_prd_9 : fst @ (ss @ ((\s, \b, b @ c_zero @ s) @ (pls @ c_one @ (snd @ (\b, b @ c_zero @ c_zero))))) @ AA @ BB = fst @ ((\p, pair @ (snd@p) @ (pls @ c_one @ (snd@p))) @ ((\s, \b, b @ c_zero @ s) @ (pls @ c_one @ (snd @ (\b, b @ c_zero @ c_zero))))) @ AA @ BB. Proof. reflexivity. Qed. Lemma check_prd_10 : fst @ ((\p, pair @ (snd@p) @ (pls @ c_one @ (snd@p))) @ ((\s, \b, b @ c_zero @ s) @ (pls @ c_one @ (snd @ (\b, b @ c_zero @ c_zero))))) @ AA @ BB -->* fst @ ((\p, pair @ (snd@p) @ (pls @ c_one @ (snd@p))) @ ((\s, \b, b @ c_zero @ s) @ (\s, \z, c_one @ s @ (c_zero @ s @ z)))) @ AA @ BB. Proof. steps. Qed. Lemma check_prd_11 : fst @ ((\p, pair @ (snd@p) @ (pls @ c_one @ (snd@p))) @ ((\s, \b, b @ c_zero @ s) @ (\s, \z, c_one @ s @ (c_zero @ s @ z)))) @ AA @ BB -->* fst @ ((\p, pair @ (snd@p) @ (pls @ c_one @ (snd@p))) @ (\b, b @ c_zero @ (\s, \z, c_one @ s @ (c_zero @ s @ z)))) @ AA @ BB. Proof. steps. Qed. Lemma check_prd_12 : fst @ ((\p, pair @ (snd@p) @ (pls @ c_one @ (snd@p))) @ (\b, b @ c_zero @ (\s, \z, c_one @ s @ (c_zero @ s @ z)))) @ AA @ BB -->* fst @ (\b, b @ (\s, \z, c_one @ s @ (c_zero @ s @ z)) @ (\s, \z, c_one @ s @ ((\s, \z, c_one @ s @ (c_zero @ s @ z)) @ s @ z))) @ AA @ BB. Proof. steps. Qed. Lemma check_prd_13 : fst @ (\b, b @ (\s, \z, c_one @ s @ (c_zero @ s @ z)) @ (\s, \z, c_one @ s @ ((\s, \z, c_one @ s @ (c_zero @ s @ z)) @ s @ z))) @ AA @ BB -->* (\s, \z, c_one @ s @ (c_zero @ s @ z)) @ AA @ BB. Proof. steps. Qed. Lemma check_prd_14 : (\s, \z, c_one @ s @ (c_zero @ s @ z)) @ AA @ BB -->* c_one @ AA @ (c_zero @ AA @ BB). Proof. steps. Qed. Lemma check_prd_15 : c_one @ AA @ (c_zero @ AA @ BB) -->* AA @ BB. Proof. steps. Qed. *) (* ---------------------------------------------------------------------- *) (* Divergence *) Notation omega := ((\x, x @ x) @ (\x, x @ x)). Lemma check_omega : omega --> omega. Proof. step. Qed. Lemma omega_not_normalizable : forall n, normalize omega n = None _. Proof. (* SOLUTION *) 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. *) (* COMMENTED OUT TO SAVE COMPILATION TIME... 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. (* Only at this point do we actually begin diverging... *) 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. (* ====================================================================== *) (* LECTURE 15 *) (* ---------------------------------------------------------------------- *) (* Recursion *) (* See TAPL for full explanations of the following... *) Notation Y_FF := ((\x, FF @ (x @ x)) @ (\x, FF @ (x @ x))). (* COMMENTED OUT TO SAVE COMPILATION TIME... Lemma check_Y_FF1 : ((\x, FF @ (x @ x)) @ (\x, FF @ (x @ x))) --> FF @ ((\x, FF @ (x @ x)) @ (\x, FF @ (x @ x))). Proof. steps. Qed. Lemma check_Y_FF2 : 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). (* COMMENTED OUT TO SAVE COMPILATION TIME... 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). (* COMMENTED OUT TO SAVE COMPILATION TIME... 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. *) Notation Z := (\f, (\y, (\x, f @ (\y, x @ x @ y)) @ (\x, f @ (\y, x @ x @ y)) @ y)). Notation f_fact := (\f, \n, test @ (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). (* COMMENTED OUT TO SAVE COMPILATION TIME... 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. steps. Qed. Lemma check_fact2 : Z_fact @ c_one @ AA @ BB -->* f_fact @ Z_fact @ c_one @ AA @ BB. Proof. steps. 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. *) (* EXERCISE: - Part 1: What is the normal form of the lambda-expression foo @ c_two @ AA @ BB given the following definitions...? (No need to hand anything in for this -- you'll just use the answer in the next part of the exercise -- but it's important to think about it on paper before starting to work with Coq...) *) Notation f_foo := (\f, \n, pls @ c_one @ (test @ (iszro @ n) @ (\z, c_zero) @ (\z, f @ (prd @ n)))). Notation foo := (Z @ f_foo). Notation Z_foo := (\y, (\x, f_foo @ (\y, x @ x @ y)) @ (\x, f_foo @ (\y, x @ x @ y)) @ y). (* - Part 2: Write a series of lemmas in the same style as above, demonstrating this. *) (* SOLUTION *) (* COMMENTED OUT TO SAVE COMPILATION TIME... Lemma check_foo0 : foo @ c_two @ AA @ BB = Z @ f_foo @ c_two @ AA @ BB. Proof. reflexivity. Qed. Lemma check_foo1 : Z @ f_foo @ c_two @ AA @ BB -->* Z_foo @ c_two @ AA @ BB. Proof. steps. Qed. Lemma check_foo2 : Z_foo @ c_two @ AA @ BB -->* f_foo @ Z_foo @ c_two @ AA @ BB. Proof. steps. Qed. Lemma check_foo3 : f_foo @ Z_foo @ c_two @ AA @ BB -->* (pls @ c_one @ (test @ (iszro @ c_two) @ (\z, c_zero) @ (\z, Z_foo @ (prd @ c_two)))) @ AA @ BB. Proof. steps. Qed. Lemma check_foo4 : (pls @ c_one @ (test @ (iszro @ c_two) @ (\z, c_zero) @ (\z, Z_foo @ (prd @ c_two)))) @ AA @ BB -->* ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (test @ fls @ (\z, c_zero) @ (\z, Z_foo @ (prd @ c_two)))) @ AA @ BB. Proof. steps. Qed. Lemma check_foo5 : ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (test @ fls @ (\z, c_zero) @ (\z, Z_foo @ (prd @ c_two)))) @ AA @ BB -->* ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ ((\z, Z_foo @ (prd @ c_two)) @ (\x,x))) @ AA @ BB. Proof. steps. Qed. Lemma check_foo6 : ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ ((\z, Z_foo @ (prd @ c_two)) @ (\x,x))) @ AA @ BB -->* ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (Z_foo @ (prd @ c_two)) ) @ AA @ BB. Proof. steps. Qed. Lemma check_foo7 : ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (Z_foo @ (prd @ c_two)) ) @ AA @ BB -->* ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (f_foo @ Z_foo @ (\s, \z, c_one @ s @ (c_zero @ s @ z))) ) @ AA @ BB. Proof. steps. Qed. Lemma check_foo8 : ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (f_foo @ Z_foo @ (\s, \z, c_one @ s @ (c_zero @ s @ z))) ) @ AA @ BB -->* ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (pls @ c_one @ (test @ (iszro @ (\s, \z, c_one @ s @ (c_zero @ s @ z))) @ (\z, c_zero) @ (\z, Z_foo @ (prd @ (\s, \z, c_one @ s @ (c_zero @ s @ z)))) ) ) ) @ AA @ BB. Proof. steps. Qed. Lemma check_foo9 : ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (pls @ c_one @ (test @ (iszro @ (\s, \z, c_one @ s @ (c_zero @ s @ z))) @ (\z, c_zero) @ (\z, Z_foo @ (prd @ (\s, \z, c_one @ s @ (c_zero @ s @ z)))) ) ) ) @ AA @ BB -->* ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (Z_foo @ c_zero) ) ) @ AA @ BB. Proof. steps. Qed. Lemma check_foo10 : ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (Z_foo @ c_zero) ) ) @ AA @ BB -->* ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (f_foo @ Z_foo @ c_zero) ) ) @ AA @ BB. Proof. steps. Qed. Lemma check_foo11 : ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (f_foo @ Z_foo @ c_zero) ) ) @ AA @ BB -->* ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (test @ tru @ (\z, c_zero) @ (\z, Z_foo @ (prd @ c_zero))) ) ) ) @ AA @ BB. Proof. steps. Qed. Lemma check_foo12 : ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (test @ tru @ (\z, c_zero) @ (\z, Z_foo @ (prd @ c_zero))) ) ) ) @ AA @ BB -->* ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (tru @ (\z, c_zero) @ (\z, Z_foo @ (prd @ c_zero)) @ (\x,x)) ) ) ) @ AA @ BB. Proof. steps. Qed. Lemma check_foo13 : ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (tru @ (\z, c_zero) @ (\z, Z_foo @ (prd @ c_zero)) @ (\x,x)) ) ) ) @ AA @ BB -->* ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (\s, \z, c_one @ s @ (c_zero @ s @ z)) ) ) @ AA @ BB. Proof. steps. Qed. Lemma check_foo14 : ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ ((\n, \s, \z, c_one @ s @ (n @ s @ z)) @ (\s, \z, c_one @ s @ (c_zero @ s @ z)) ) ) @ AA @ BB -->* (\s, \z, c_one @ s @ ((\s, \z, c_one @ s @ ((\s, \z, c_one @ s @ (c_zero @ s @ z)) @ s @ z)) @ s @ z)) @ AA @ BB. Proof. steps. Qed. Lemma check_foo15 : (\s, \z, c_one @ s @ ((\s, \z, c_one @ s @ ((\s, \z, c_one @ s @ (c_zero @ s @ z)) @ s @ z)) @ s @ z)) @ AA @ BB -->* (c_one @ AA @ ((\s, \z, c_one @ s @ ((\s, \z, c_one @ s @ (c_zero @ s @ z)) @ s @ z)) @ AA @ BB)). Proof. steps. Qed. Lemma check_foo16 : (c_one @ AA @ ((\s, \z, c_one @ s @ ((\s, \z, c_one @ s @ (c_zero @ s @ z)) @ s @ z)) @ AA @ BB)) -->* AA @ (AA @ (AA @ BB)). Proof. steps. Qed. *) End LambdaExamplesAgain. (* ====================================================================== *) (* Properties of evaluation *) (* Now that we've developed a little intuition about what the lambda-calculus is like by writing programs in it, it's time to turn our attention to some of its theoretical properties... *) (* ---------------------------------------------------------------------- *) (* Progress *) (* Since "everything is a function in the lambda-calculus," we might expect that a progress theorem would hold for this language. This is intuitively true, but we need to be a little careful about how we state the details. First, if we consider terms containing constants, then it certainly *is* possible to have a term that is stuck -- a normal form but not a value. For example, the term [AA @ (\x,x)] is stuck. Since we are mainly interested in the properties of the pure lambda-calculus, such examples need not worry us. But if we want to state a progress theorem that's true, we need to eliminate them by restricting attention to "pure terms"... *) Inductive pure : tm -> Prop := | p_var : forall x, pure (tm_var x) | p_app : forall t1 t2, pure t1 -> pure t2 -> pure (t1 @ t2) | p_abs : forall x t1, pure t1 -> pure (\x,t1). Lemma pure__not_only_constants : forall t, pure t -> only_constants t = no. Proof. intros t P. induction P. CASE "p_var". reflexivity. CASE "p_app". simpl. rewrite IHP1. rewrite IHP2. reflexivity. CASE "p_abs". reflexivity. Qed. (* This helps, but it's not quite enough. Terms like [x @ y] are also stuck, because we didn't include variables in the set of values. There are technical reasons for doing things this way (it simplifies the definition of substitution, as well see when we look at full beta-reduction in a few minutes). So we should leave the definition of value as it is but refine the statement of the progress theorem so that it only applies to terms with no variables "free" at the top level. *) Inductive appears_free_in : name -> tm -> Prop := | afi_var : forall x, appears_free_in x (tm_var x) | afi_app1 : forall x t1 t2, appears_free_in x t1 -> appears_free_in x (t1 @ t2) | afi_app2 : forall x t1 t2, appears_free_in x t2 -> appears_free_in x (t1 @ t2) | afi_abs : forall x y t1, eqname x y = no -> appears_free_in x t1 -> appears_free_in x (\y,t1). Definition closed (t:tm) := forall x, ~ appears_free_in x t. Theorem pure_closed_terms_are_not_stuck : forall t, pure t -> closed t -> (value t \/ exists t', eval t t'). Proof. intros t HP. induction HP. CASE "var". intros C. unfold closed in C. assert (appears_free_in x (!x)). SCASE "Pf of assertion". apply afi_var. unfold not in C. apply C with (x0 := x) in H. solve by inversion. CASE "app". intros H. unfold closed in H. assert (closed t1). SCASE "Pf of assertion". unfold closed. intros x Contra. assert (appears_free_in x (t1@t2)). SSCASE "Pf of assertion". apply afi_app1. assumption. apply H with (x:=x). assumption. assert (value t1 \/ (exists t' : tm, eval t1 t')). apply IHHP1. assumption. assert (closed t2). SCASE "Pf of assertion". unfold closed. intros x Contra. assert (appears_free_in x (t1@t2)). SSCASE "Pf of assertion". apply afi_app2. assumption. apply H with (x:=x). assumption. assert (value t2 \/ (exists t' : tm, eval t2 t')). apply IHHP2. assumption. apply or_intror. inversion H1; inversion H3; subst. SCASE "t1 value / t2 value". inversion H4. SSCASE "constant value". apply pure__not_only_constants in HP1. rewrite HP1 in H6. solve by inversion. SSCASE "abstraction value". apply ex_intro with (witness := {x |-> t2}t). apply E_AppAbs. assumption. SCASE "t1 value / t2 steps". inversion H5. apply ex_intro with (witness := t1 @ witness). apply E_App2. assumption. assumption. SCASE "t1 steps / t2 value". inversion H4. apply ex_intro with (witness := witness @ t2). apply E_App1. assumption. SCASE "t1 steps / t2 steps". inversion H4. apply ex_intro with (witness := witness @ t2). apply E_App1. assumption. CASE "abs". intros H. apply or_introl. apply v_abs. Qed. (* ---------------------------------------------------------------------- *) (* Call-by-name evaluation *) Inductive eval_cbn : tm -> tm -> Prop := | En_AppAbs : forall x t12 v2, eval_cbn ((\x, t12) @ v2) ({x |-> v2} t12) | En_App1 : forall t1 t1' t2, eval_cbn t1 t1' -> eval_cbn (t1 @ t2) (t1' @ t2). Fixpoint simplify_step_cbn (t:tm) {struct t} : option tm := match t with | t1 @ t2 => match t1 with | \x,t12 => Some _ (({x |-> t2} t12)) | _ => match simplify_step_cbn t1 with | None => None _ | Some t1' => Some _ (t1' @ t2) end end | _ => None _ end. Lemma simplify_step_cbn__eval_cbn : forall t t', simplify_step_cbn t = Some _ t' -> eval_cbn t t'. Proof. (* SOLUTION *) (tm_cases (induction t) CASE); intros t' S; try solve [solve by inversion]. CASE "tm_app". simpl in S. (tm_cases (destruct t1) SCASE); simpl. SCASE "tm_const". solve by inversion. SCASE "tm_var". solve by inversion. SCASE "tm_app". destruct (simplify_step_cbn (t1_1 @ t1_2)). SSCASE "t1 steps". inversion S. apply En_App1. apply IHt1. reflexivity. SSCASE "t1 doesn't step". solve by inversion. SCASE "tm_abs". inversion S. apply En_AppAbs. Qed. (* ---------------------------------------------------------------------- *) (* Nondeterministic outer evaluation *) Inductive eval_ndo : tm -> tm -> Prop := | Endo_AppAbs : forall x t12 v2, eval_ndo ((\x, t12) @ v2) ({x |-> v2} t12) | Endo_App1 : forall t1 t1' t2, eval_ndo t1 t1' -> eval_ndo (t1 @ t2) (t1' @ t2) | Endo_App2 : forall t1 t2 t2', eval_ndo t2 t2' -> eval_ndo (t1 @ t2) (t1 @ t2'). (* ---------------------------------------------------------------------- *) (* Full nondeterministic evaluation *) (* Also known as FULL BETA-REDUCTION (because the "beta-reduction rule," Efull_AppAbs, can be applied anywhere in the term at each step). *) Inductive eval_full : tm -> tm -> Prop := | Efull_AppAbs : forall x t12 v2, eval_full ((\x, t12) @ v2) ({x |-> v2} t12) | Efull_App1 : forall t1 t1' t2, eval_full t1 t1' -> eval_full (t1 @ t2) (t1' @ t2) | Efull_App2 : forall t1 t2 t2', eval_full t2 t2' -> eval_full (t1 @ t2) (t1 @ t2') | Efull_Abs : forall x t1 t1', eval_full t1 t1' -> eval_full (\x, t1) (\x, t1'). (* However, something is a little bit wrong with this definition... *) (* Remember the principle that renaming a bound variable should not change a program's meaning: if [y] is not free in [t], then [\x,t] and [\y, {x|->y}t] should behave exactly the same. Unfortunately, if we allow evaluation under lambda abstractions (as we are doing here), this property breaks... *) Module LambdaExamplesContd. Export LambdaExamplesAgain. Lemma uh_oh_1 : eval_full (\y, (\x, \y, x) @ (\z, y)) (\y, (\y, \z, y)). Proof. apply Efull_Abs. assert ({x |-> (\z, y)}(\y, x) = (\y, \z, y)). reflexivity. rewrite <- H. apply Efull_AppAbs. Qed. Lemma uh_oh_2 : eval_full (\y, (\x, \w, x) @ (\z, y)) (\y, (\w, \z, y)). Proof. apply Efull_Abs. assert ({x |-> (\z, y)}(\w, x) = (\w, \z, y)). reflexivity. rewrite <- H. apply Efull_AppAbs. Qed. (* But these results -- [\y, (\y, \z, y)] and [\y, (\w, \z, y)] -- behave differently! (I.e., just renaming a bound variable caused reduction to give us different answers). For example, (\y, (\y, \z, y)) omega has a normal form, while (\y, (\w, \z, y)) omega does not. *) (* OPTIONAL EXERCISE: Think about how to redefine the substitution function to avoid this problem. Then read the end of TAPL chapter 5. *) End LambdaExamplesContd. End LambdaContd.