diff -r 78d828f43cdf -r 4b4742aa43f2 Tutorial/Tutorial2s.thy --- a/Tutorial/Tutorial2s.thy Sat Dec 17 16:58:11 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,354 +0,0 @@ - -theory Tutorial2s -imports Lambda -begin - -section {* Height of a Lambda-Term *} - -text {* - The theory Lambda defines the notions of capture-avoiding - substitution and the height of lambda terms. -*} - -thm height.simps -thm subst.simps - -subsection {* EXERCISE 7 *} - -text {* - Lets prove a property about the height of substitutions. - - Assume that the height of a lambda-term is always greater - or equal to 1. -*} - -lemma height_ge_one: - shows "1 \ height t" -by (induct t rule: lam.induct) (auto) - -text {* Remove the sorries *} - -theorem - shows "height (t[x ::= t']) \ height t - 1 + height t'" -proof (nominal_induct t avoiding: x t' rule: lam.strong_induct) - case (Var y) - have "1 \ height t'" using height_ge_one by simp - then show "height (Var y[x ::= t']) \ height (Var y) - 1 + height t'" by simp -next - case (App t1 t2) - have ih1: "height (t1[x::=t']) \ (height t1) - 1 + height t'" - and ih2: "height (t2[x::=t']) \ (height t2) - 1 + height t'" by fact+ - then show "height ((App t1 t2)[x ::= t']) \ height (App t1 t2) - 1 + height t'" by simp -next - case (Lam y t1) - have ih: "height (t1[x::=t']) \ height t1 - 1 + height t'" by fact - moreover - have vc: "atom y \ x" "atom y \ t'" by fact+ -- {* usual variable convention *} - ultimately - show "height ((Lam [y].t1)[x ::= t']) \ height (Lam [y].t1) - 1 + height t'" by simp -qed - - -section {* Types and the Weakening Lemma *} - -nominal_datatype ty = - tVar "string" -| tArr "ty" "ty" (infixr "\" 100) - - -text {* - Having defined them as nominal datatypes gives us additional - definitions and theorems that come with types (see below). - - We next define the type of typing contexts, a predicate that - defines valid contexts (i.e. lists that contain only unique - variables) and the typing judgement. -*} - -type_synonym ty_ctx = "(name \ ty) list" - -inductive - valid :: "ty_ctx \ bool" -where - v1[intro]: "valid []" -| v2[intro]: "\valid \; atom x \ \\\ valid ((x, T) # \)" - - -inductive - typing :: "ty_ctx \ lam \ ty \ bool" ("_ \ _ : _" [60, 60, 60] 60) -where - t_Var[intro]: "\valid \; (x, T) \ set \\ \ \ \ Var x : T" -| t_App[intro]: "\\ \ t1 : T1 \ T2; \ \ t2 : T1\ \ \ \ App t1 t2 : T2" -| t_Lam[intro]: "\atom x \ \; (x, T1) # \ \ t : T2\ \ \ \ Lam [x].t : T1 \ T2" - - -text {* - The predicate atom x \ \, read as x fresh for \, is defined by - Nominal Isabelle. It is defined for lambda-terms, products, lists etc. - For example we have: -*} - -lemma - fixes x::"name" - shows "atom x \ Lam [x].t" - and "atom x \ (t1, t2) \ atom x \ App t1 t2" - and "atom x \ Var y \ atom x \ y" - and "\atom x \ t1; atom x \ t2\ \ atom x \ (t1, t2)" - and "\atom x \ l1; atom x \ l2\ \ atom x \ (l1 @ l2)" - and "atom x \ y \ x \ y" - by (simp_all add: lam.fresh fresh_append fresh_at_base) - -text {* - We can also prove that every variable is fresh for a type. -*} - -lemma ty_fresh: - fixes x::"name" - and T::"ty" - shows "atom x \ T" -by (induct T rule: ty.induct) - (simp_all add: ty.fresh pure_fresh) - -text {* - In order to state the weakening lemma in a convenient form, we - using the following abbreviation. Abbreviations behave like - definitions, except that they are always automatically folded - and unfolded. -*} - -abbreviation - "sub_ty_ctx" :: "ty_ctx \ ty_ctx \ bool" ("_ \ _" [60, 60] 60) -where - "\1 \ \2 \ \x. x \ set \1 \ x \ set \2" - - -subsection {* EXERCISE 8 *} - -text {* - Fill in the details and give a proof of the weakening lemma. -*} - -lemma - assumes a: "\1 \ t : T" - and b: "valid \2" - and c: "\1 \ \2" - shows "\2 \ t : T" -using a b c -proof (induct arbitrary: \2) - case (t_Var \1 x T) - have a1: "valid \1" by fact - have a2: "(x, T) \ set \1" by fact - have a3: "valid \2" by fact - have a4: "\1 \ \2" by fact - - show "\2 \ Var x : T" sorry -next - case (t_Lam x \1 T1 t T2) - have ih: "\\3. \valid \3; (x, T1) # \1 \ \3\ \ \3 \ t : T2" by fact - have a0: "atom x \ \1" by fact - have a1: "valid \2" by fact - have a2: "\1 \ \2" by fact - - show "\2 \ Lam [x].t : T1 \ T2" sorry -qed (auto) -- {* the application case is automatic*} - - -text {* - Despite the frequent claim that the weakening lemma is trivial, - routine or obvious, the proof in the lambda-case does not go - through smoothly. Painful variable renamings seem to be necessary. - But the proof using renamings is horribly complicated (see below). -*} - -equivariance valid -equivariance typing - -lemma weakening_NOT_TO_BE_TRIED_AT_HOME: - assumes a: "\1 \ t : T" - and b: "valid \2" - and c: "\1 \ \2" - shows "\2 \ t : T" -using a b c -proof (induct arbitrary: \2) - -- {* lambda case *} - case (t_Lam x \1 T1 t T2) - have fc0: "atom x \ \1" by fact - have ih: "\\3. \valid \3; (x, T1) # \1 \ \3\ \ \3 \ t : T2" by fact - -- {* we choose a fresh variable *} - obtain c::"name" where fc1: "atom c \ (x, t, \1, \2)" by (rule obtain_fresh) - -- {* we alpha-rename the abstraction *} - have "Lam [c].((c \ x) \ t) = Lam [x].t" using fc1 - by (auto simp add: lam.eq_iff Abs1_eq_iff flip_def) - moreover - -- {* we can then alpha rename the goal *} - have "\2 \ Lam [c].((c \ x) \ t) : T1 \ T2" - proof - - -- {* we need to establish *} - -- {* (1) (x, T1) # \1 \ (x, T1) # ((c \ x) \ \2) *} - -- {* (2) valid ((x, T1) # ((c \ x) \ \2)) *} - have "(1)": "(x, T1) # \1 \ (x, T1) # ((c \ x) \ \2)" - proof - - have "\1 \ \2" by fact - then have "(c \ x) \ ((x, T1) # \1 \ (x, T1) # ((c \ x) \ \2))" using fc0 fc1 - by (perm_simp) (simp add: flip_fresh_fresh) - then show "(x, T1) # \1 \ (x, T1) # ((c \ x) \ \2)" by (rule permute_boolE) - qed - moreover - have "(2)": "valid ((x, T1) # ((c \ x) \ \2))" - proof - - have "valid \2" by fact - then show "valid ((x, T1) # ((c \ x) \ \2))" using fc1 - by (auto simp add: fresh_permute_left atom_eqvt valid.eqvt) - qed - -- {* these two facts give us by induction hypothesis the following *} - ultimately have "(x, T1) # ((c \ x) \ \2) \ t : T2" using ih by simp - -- {* we now apply renamings to get to our goal *} - then have "(c \ x) \ ((x, T1) # ((c \ x) \ \2) \ t : T2)" by (rule permute_boolI) - then have "(c, T1) # \2 \ ((c \ x) \ t) : T2" using fc1 - by (perm_simp) (simp add: flip_fresh_fresh ty_fresh) - then show "\2 \ Lam [c].((c \ x) \ t) : T1 \ T2" using fc1 by auto - qed - ultimately show "\2 \ Lam [x].t : T1 \ T2" by simp -qed (auto) -- {* var and app cases, luckily, are automatic *} - - -text {* - The remedy is to use again a stronger induction principle that - has the usual "variable convention" already build in. The - following command derives this induction principle for the typing - relation. (We shall explain what happens here later.) -*} - -nominal_inductive typing - avoids t_Lam: "x" - unfolding fresh_star_def - by (simp_all add: fresh_Pair lam.fresh ty_fresh) - -text {* Compare the two induction principles *} - -thm typing.induct -thm typing.strong_induct -- {* note the additional assumption {atom x} \ c *} - -text {* - We can use the stronger induction principle by replacing - the line - - proof (induct arbitrary: \2) - - with - - proof (nominal_induct avoiding: \2 rule: typing.strong_induct) - - Try now the proof. -*} - -subsection {* EXERCISE 9 *} - -lemma weakening: - assumes a: "\1 \ t : T" - and b: "valid \2" - and c: "\1 \ \2" - shows "\2 \ t : T" -using a b c -proof (nominal_induct avoiding: \2 rule: typing.strong_induct) - case (t_Var \1 x T) -- {* variable case is as before *} - have "\1 \ \2" by fact - moreover - have "valid \2" by fact - moreover - have "(x, T)\ set \1" by fact - ultimately show "\2 \ Var x : T" by auto -next - case (t_Lam x \1 T1 t T2) - have vc: "atom x \ \2" by fact -- {* additional fact afforded by the strong induction *} - have ih: "\\3. \valid \3; (x, T1) # \1 \ \3\ \ \3 \ t : T2" by fact - have a0: "atom x \ \1" by fact - have a1: "valid \2" by fact - have a2: "\1 \ \2" by fact - have "valid ((x, T1) # \2)" using a1 vc by auto - moreover - have "(x, T1) # \1 \ (x, T1) # \2" using a2 by auto - ultimately - have "(x, T1) # \2 \ t : T2" using ih by simp - then show "\2 \ Lam [x].t : T1 \ T2" using vc by auto -qed (auto) -- {* app case *} - - - -section {* Unbind and an Inconsistency Example *} - -text {* - You might wonder why we had to discharge some proof - obligations in order to obtain the stronger induction - principle for the typing relation. (Remember for - lambda terms this stronger induction principle is - derived automatically.) - - This proof obligation is really needed, because if we - assume universally a stronger induction principle, then - in some cases we can derive false. This is "shown" below. -*} - - -inductive - unbind :: "lam \ lam \ bool" (infixr "\" 60) -where - u_Var[intro]: "Var x \ Var x" -| u_App[intro]: "App t1 t2 \ App t1 t2" -| u_Lam[intro]: "t \ t' \ Lam [x].t \ t'" - -text {* It is clear that the following judgement holds. *} - -lemma unbind_simple: - shows "Lam [x].Var x \ Var x" - by auto - -text {* - Now lets derive the strong induction principle for unbind. - The point is that we cannot establish the proof obligations, - therefore we force Isabelle to accept them by using "sorry". -*} - -equivariance unbind -nominal_inductive unbind - avoids u_Lam: "x" - sorry - -text {* - Using the stronger induction principle, we can establish - th follwoing bogus property. -*} - -lemma unbind_fake: - fixes y::"name" - assumes a: "t \ t'" - and b: "atom y \ t" - shows "atom y \ t'" -using a b -proof (nominal_induct avoiding: y rule: unbind.strong_induct) - case (u_Lam t t' x y) - have ih: "atom y \ t \ atom y \ t'" by fact - have asm: "atom y \ Lam [x]. t" by fact - have fc: "atom x \ y" by fact - then have in_eq: "x \ y" by (simp add: fresh_at_base) - then have "atom y \ t" using asm by (simp add: lam.fresh) - then show "atom y \ t'" using ih by simp -qed - -text {* - And from this follows the inconsitency: -*} - -lemma - shows "False" -proof - - have "atom x \ Lam [x]. Var x" by (simp add: lam.fresh) - moreover - have "Lam [x]. Var x \ Var x" using unbind_simple by auto - ultimately - have "atom x \ Var x" using unbind_fake by auto - then have "x \ x" by (simp add: lam.fresh fresh_at_base) - then show "False" by simp -qed - -end