(* $Id: sol.thy,v 1.2 2004/11/23 15:14:35 webertj Exp $ Author: Tobias Nipkow *) header {* Context-Free Grammars *} (*<*) theory sol imports Main begin (*>*) text {* This exercise is concerned with context-free grammars (CFGs). Please read section 7.4 in the tutorial which explains how to model CFGs as inductive definitions. Our particular example is about defining valid sequences of parentheses. *} subsection {* Two grammars *} text{* The most natural definition of valid sequences of parentheses is this: \[ S \quad\to\quad \varepsilon \quad\mid\quad '('~S~')' \quad\mid\quad S~S \] where $\varepsilon$ is the empty word. A second, somewhat unusual grammar is the following one: \[ T \quad\to\quad \varepsilon \quad\mid\quad T~'('~T~')' \] Model both grammars as inductive sets $S$ and $T$ and prove $S = T$. *} text {* The alphabet: *} datatype alpha = A | B text{* Standard grammar: *} inductive_set S :: "alpha list set" where S1: "[] : S" | S2: "w : S \<Longrightarrow> A#w@[B] : S" | S3: "v : S \<Longrightarrow> w : S \<Longrightarrow> v @ w : S" declare S1 [iff] S2[intro!,simp] text{* Nonstandard grammar: *} inductive_set T :: "alpha list set" where T1: "[] : T" | T23: "v : T \<Longrightarrow> w : T \<Longrightarrow> v @ A # w @ [B]: T" declare T1 [iff] text {* @{text T} is a subset of @{text S}: *} lemma T2S: "w : T \<Longrightarrow> w : S" apply(erule T.induct) apply simp apply(blast intro: S3) done text {* @{text S} is a subset of @{text T}: *} lemma T2: "w : T \<Longrightarrow> A#w@[B] : T" using T23[where v = "[]"] by simp lemma T3: "v : T \<Longrightarrow> u : T \<Longrightarrow> u@v : T" apply(erule T.induct) apply fastsimp apply(simp add: append_assoc[symmetric] del:append_assoc) apply(blast intro: T23) done lemma S2T: "w : S \<Longrightarrow> w : T" apply(erule S.induct) apply simp apply(blast intro: T2) apply(blast intro: T3) done text {* @{text "S = T"}: *} lemma "S = T" by(blast intro: S2T T2S) subsection {* A recursive function *} text {* Instead of a grammar, we can also define valid sequences of parentheses via a test function: traverse the word from left to right while counting how many closing parentheses are still needed. If the counter is 0 at the end, the sequence is valid. Define this recursive function and prove that a word is in $S$ iff it is accepted by your function. The $\Longrightarrow$ direction is easy, the other direction more complicated. *} consts balanced :: "alpha list * nat \<Rightarrow> bool" recdef balanced "measure(%(xs,n). length xs)" "balanced ([], 0) = True" "balanced (A#w, n) = balanced(w,Suc n)" "balanced (B#w, Suc n) = balanced(w,n)" "balanced (w, n) = False" text {* Correctness of the recognizer w.r.t.\ @{text S}: *} lemma [simp]: "balanced(w,n) \<Longrightarrow> balanced(w@[B],Suc n)" apply(induct w n rule:balanced.induct) apply simp_all done lemma [simp]: "\<lbrakk>balanced (v, n); balanced (w, 0)\<rbrakk> \<Longrightarrow> balanced (v @ w, n)" apply(induct v n rule:balanced.induct) apply simp_all done lemma "w : S \<Longrightarrow> balanced(w,0)" apply(erule S.induct) apply simp_all done text {* Completeness of the recognizer w.r.t.\ @{text S}: *} lemma [iff]: "[A,B] : S" using S2[where w = "[]"] by simp lemma AB: assumes u: "u \<in> S" shows "\<And>v w. u = v@w \<Longrightarrow> v @ A # B # w \<in> S" using u proof(induct) case S1 thus ?case by simp next case (S2 u) have uS: "u \<in> S" and IH: "\<And>v w. u = v @ w \<Longrightarrow> v @ A # B # w \<in> S" and asm: "A # u @ [B] = v @ w" . show "v @ A # B # w \<in> S" proof (cases v) case Nil hence "w = A # u @ [B]" using asm by simp hence "w \<in> S" using uS by simp hence "[A,B] @ w \<in> S" by(blast intro:S3) thus ?thesis using Nil by simp next case (Cons x v') show ?thesis proof (cases w rule:rev_cases) case Nil from uS have "(A # u @ [B]) @ [A,B] \<in> S" by(blast intro:S3) thus ?thesis using Nil Cons asm by auto next case (snoc w' y) hence u: "u = v' @ w'" and [simp]: "x = A & y = B" using Cons asm by auto from u have "v' @ A # B # w' \<in> S" by(rule IH) hence "A # (v' @ A # B # w') @ [B] \<in> S" by(rule S.S2) thus ?thesis using Cons snoc by auto qed qed next case (S3 v' w') have v'S: "v' \<in> S" and w'S: "w' \<in> S" and IHv: "\<And>v w. v' = v @ w \<Longrightarrow> v @ A # B # w \<in> S" and IHw: "\<And>v w. w' = v @ w \<Longrightarrow> v @ A # B # w \<in> S" and asm: "v' @ w' = v @ w" . then obtain r where "v' = v @ r \<and> r @ w' = w \<or> v' @ r = v \<and> w' = r @ w" (is "?A \<or> ?B") by (auto simp:append_eq_append_conv2) thus "v @ A # B # w \<in> S" proof assume A: ?A hence "v @ A # B # r \<in> S" using IHv by blast hence "(v @ A # B # r) @ w' \<in> S" using w'S by(rule S.S3) thus ?thesis using A by auto next assume B: ?B hence "r @ A # B # w \<in> S" using IHw by blast with v'S have "v' @ (r @ A # B # w) \<in> S" by(rule S.S3) thus ?thesis using B by auto qed qed text {* The same lemma for friends of the apply style: *} lemma "u \<in> S \<Longrightarrow> ALL v w. u = v@w \<longrightarrow> v @ A # B # w \<in> S" apply(erule S.induct) apply simp apply(rename_tac u) apply (clarsimp simp:Cons_eq_append_conv) apply(rule conjI) apply (clarsimp) apply(subgoal_tac "[A,B] @ (A # u @ [B]) : S") apply(simp) apply(blast intro:S3) apply(clarsimp simp:append_eq_append_conv2 Cons_eq_append_conv) apply(rename_tac w w1 w2) apply(erule disjE) apply clarsimp apply(subgoal_tac "A # (w1 @ A # B # w2) @ [B] : S") apply simp apply(blast intro:S3) apply clarsimp apply(erule disjE) apply clarsimp apply(subgoal_tac "A # (u @ [A,B]) @ [B] : S") apply(simp) apply(blast intro:S3) apply clarsimp apply(subgoal_tac "(A # u @ [B]) @ [A,B] : S") apply(simp) apply(blast intro:S3) apply(clarsimp simp:append_eq_append_conv2) apply(rename_tac u v w x y) apply(erule disjE) apply clarsimp apply(subgoal_tac "(w @ A # B # y) @ v : S") apply(simp) apply(blast intro:S3) apply clarsimp apply(blast intro:S3) done lemma "balanced(w,n) \<Longrightarrow> replicate n A @ w : S" apply (induct w n rule:balanced.induct) apply (simp_all add:replicate_app_Cons_same) apply (simp add:replicate_app_Cons_same[symmetric]) apply (simp add: AB) done (*<*) end (*>*)