header "A Typed Language" theory Types imports Complex_Main begin subsection "Arithmetic Expressions" datatype val = Iv int | Rv real types name = nat state = "name \ val" datatype aexp = Ic int | Rc real | V name | Plus aexp aexp inductive taval :: "aexp \ state \ val \ bool" where "taval (Ic i) s (Iv i)" | "taval (Rc r) s (Rv r)" | "taval (V x) s (s x)" | "taval a\<^isub>1 s (Iv i\<^isub>1) \ taval a\<^isub>2 s (Iv i\<^isub>2) \ taval (Plus a\<^isub>1 a\<^isub>2) s (Iv(i\<^isub>1+i\<^isub>2))" | "taval a\<^isub>1 s (Rv r\<^isub>1) \ taval a\<^isub>2 s (Rv r\<^isub>2) \ taval (Plus a\<^isub>1 a\<^isub>2) s (Rv(r\<^isub>1+r\<^isub>2))" inductive_cases [elim!]: "taval (Ic i) s v" "taval (Rc i) s v" "taval (V x) s v" "taval (Plus a1 a2) s v" subsection "Boolean Expressions" datatype bexp = B bool | Not bexp | And bexp bexp | Less aexp aexp inductive tbval :: "bexp \ state \ bool \ bool" where "tbval (B bv) s bv" | "tbval b s bv \ tbval (Not b) s (\ bv)" | "tbval b\<^isub>1 s bv\<^isub>1 \ tbval b\<^isub>2 s bv\<^isub>2 \ tbval (And b\<^isub>1 b\<^isub>2) s (bv\<^isub>1 & bv\<^isub>2)" | "taval a\<^isub>1 s (Iv i\<^isub>1) \ taval a\<^isub>2 s (Iv i\<^isub>2) \ tbval (Less a\<^isub>1 a\<^isub>2) s (i\<^isub>1 < i\<^isub>2)" | "taval a\<^isub>1 s (Rv r\<^isub>1) \ taval a\<^isub>2 s (Rv r\<^isub>2) \ tbval (Less a\<^isub>1 a\<^isub>2) s (r\<^isub>1 < r\<^isub>2)" subsection "Syntax of Commands" (* a copy of Com.thy - keep in sync! *) datatype com = SKIP | Assign name aexp ("_ ::= _" [1000, 61] 61) | Semi com com ("_; _" [60, 61] 60) | If bexp com com ("IF _ THEN _ ELSE _" [0, 0, 61] 61) | While bexp com ("WHILE _ DO _" [0, 61] 61) subsection "Small-Step Semantics of Commands" inductive small_step :: "(com \ state) \ (com \ state) \ bool" (infix "\" 55) where Assign: "taval a s v \ (x ::= a, s) \ (SKIP, s(x := v))" | Semi1: "(SKIP;c,s) \ (c,s)" | Semi2: "(c\<^isub>1,s) \ (c\<^isub>1',s') \ (c\<^isub>1;c\<^isub>2,s) \ (c\<^isub>1';c\<^isub>2,s')" | IfTrue: "tbval b s True \ (IF b THEN c\<^isub>1 ELSE c\<^isub>2,s) \ (c\<^isub>1,s)" | IfFalse: "tbval b s False \ (IF b THEN c\<^isub>1 ELSE c\<^isub>2,s) \ (c\<^isub>2,s)" | While: "(WHILE b DO c,s) \ (IF b THEN c; WHILE b DO c ELSE SKIP,s)" lemmas small_step_induct = small_step.induct[split_format(complete)] subsection "The Type System" datatype ty = Ity | Rty types tyenv = "name \ ty" inductive atyping :: "tyenv \ aexp \ ty \ bool" ("(1_/ \/ (_ :/ _))" [50,0,50] 50) where Ic_ty: "\ \ Ic i : Ity" | Rc_ty: "\ \ Rc r : Rty" | V_ty: "\ \ V x : \ x" | Plus_ty: "\ \ a\<^isub>1 : \ \ \ \ a\<^isub>2 : \ \ \ \ Plus a\<^isub>1 a\<^isub>2 : \" text{* Warning: the ``:'' notation leads to syntactic ambiguities, i.e. multiple parse trees, because ``:'' also stands for set membership. In most situations Isabelle's type system will reject all but one parse tree, but will still inform you of the potential ambiguity. *} inductive btyping :: "tyenv \ bexp \ bool" (infix "\" 50) where B_ty: "\ \ B bv" | Not_ty: "\ \ b \ \ \ Not b" | And_ty: "\ \ b\<^isub>1 \ \ \ b\<^isub>2 \ \ \ And b\<^isub>1 b\<^isub>2" | Less_ty: "\ \ a\<^isub>1 : \ \ \ \ a\<^isub>2 : \ \ \ \ Less a\<^isub>1 a\<^isub>2" inductive ctyping :: "tyenv \ com \ bool" (infix "\" 50) where Skip_ty: "\ \ SKIP" | Assign_ty: "\ \ a : \(x) \ \ \ x ::= a" | Semi_ty: "\ \ c\<^isub>1 \ \ \ c\<^isub>2 \ \ \ c\<^isub>1;c\<^isub>2" | If_ty: "\ \ b \ \ \ c\<^isub>1 \ \ \ c\<^isub>2 \ \ \ IF b THEN c\<^isub>1 ELSE c\<^isub>2" | While_ty: "\ \ b \ \ \ c \ \ \ WHILE b DO c" inductive_cases [elim!]: "\ \ x ::= a" "\ \ c1;c2" "\ \ IF b THEN c\<^isub>1 ELSE c\<^isub>2" "\ \ WHILE b DO c" subsection "Well-typed Programs Do Not Get Stuck" fun type :: "val \ ty" where "type (Iv i) = Ity" | "type (Rv r) = Rty" lemma [simp]: "type v = Ity \ (\i. v = Iv i)" by (cases v) simp_all lemma [simp]: "type v = Rty \ (\r. v = Rv r)" by (cases v) simp_all definition styping :: "tyenv \ state \ bool" (infix "\" 50) where "\ \ s \ (\x. type (s x) = \ x)" lemma apreservation: "\ \ a : \ \ taval a s v \ \ \ s \ type v = \" apply(induct arbitrary: v rule: atyping.induct) apply (fastsimp simp: styping_def)+ done lemma aprogress: "\ \ a : \ \ \ \ s \ \v. taval a s v" proof(induct rule: atyping.induct) case (Plus_ty \ a1 t a2) then obtain v1 v2 where v: "taval a1 s v1" "taval a2 s v2" by blast show ?case proof (cases v1) case Iv with Plus_ty(1,3,5) v show ?thesis by(fastsimp intro: taval.intros(4) dest!: apreservation) next case Rv with Plus_ty(1,3,5) v show ?thesis by(fastsimp intro: taval.intros(5) dest!: apreservation) qed qed (auto intro: taval.intros) lemma bprogress: "\ \ b \ \ \ s \ \v. tbval b s v" proof(induct rule: btyping.induct) case (Less_ty \ a1 t a2) then obtain v1 v2 where v: "taval a1 s v1" "taval a2 s v2" by (metis aprogress) show ?case proof (cases v1) case Iv with Less_ty v show ?thesis by (fastsimp intro!: tbval.intros(4) dest!:apreservation) next case Rv with Less_ty v show ?thesis by (fastsimp intro!: tbval.intros(5) dest!:apreservation) qed qed (auto intro: tbval.intros) theorem progress: "\ \ c \ \ \ s \ c \ SKIP \ \cs'. (c,s) \ cs'" proof(induct rule: ctyping.induct) case Skip_ty thus ?case by simp next case Assign_ty thus ?case by (metis Assign aprogress) next case Semi_ty thus ?case by simp (metis Semi1 Semi2) next case (If_ty \ b c1 c2) then obtain bv where "tbval b s bv" by (metis bprogress) show ?case proof(cases bv) assume "bv" with `tbval b s bv` show ?case by simp (metis IfTrue) next assume "\bv" with `tbval b s bv` show ?case by simp (metis IfFalse) qed next case While_ty show ?case by (metis While) qed theorem styping_preservation: "(c,s) \ (c',s') \ \ \ c \ \ \ s \ \ \ s'" proof(induct rule: small_step_induct) case Assign thus ?case by (auto simp: styping_def) (metis Assign(1,3) apreservation) qed auto theorem ctyping_preservation: "(c,s) \ (c',s') \ \ \ c \ \ \ c'" by (induct rule: small_step_induct) (auto simp: ctyping.intros) inductive small_steps :: "com * state \ com * state \ bool" (infix "\*" 55) where refl: "cs \* cs" | step: "cs \ cs' \ cs' \* cs'' \ cs \* cs''" lemmas small_steps_induct = small_steps.induct[split_format(complete)] theorem type_sound: "(c,s) \* (c',s') \ \ \ c \ \ \ s \ c' \ SKIP \ \cs''. (c',s') \ cs''" apply(induct rule:small_steps_induct) apply (metis progress) by (metis styping_preservation ctyping_preservation) end