lib/monads: improve style of nondet and trace

Signed-off-by: Corey Lewis <corey.lewis@proofcraft.systems>
This commit is contained in:
Corey Lewis 2023-10-05 13:18:14 +11:00 committed by Corey Lewis
parent 293b97cb17
commit 3333395cc3
15 changed files with 219 additions and 140 deletions

View File

@ -277,7 +277,8 @@ lemma monad_state_eqI [intro]:
subsection \<open>General @{const whileLoop} reasoning\<close>
definition whileLoop_terminatesE ::
"('a \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> ('a \<Rightarrow> ('s, 'e + 'a) nondet_monad) \<Rightarrow> 'a \<Rightarrow> 's \<Rightarrow> bool" where
"('a \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> ('a \<Rightarrow> ('s, 'e + 'a) nondet_monad) \<Rightarrow> 'a \<Rightarrow> 's \<Rightarrow> bool"
where
"whileLoop_terminatesE C B \<equiv>
\<lambda>r. whileLoop_terminates (\<lambda>r s. case r of Inr v \<Rightarrow> C v s | _ \<Rightarrow> False) (lift B) (Inr r)"

View File

@ -71,16 +71,15 @@ text \<open>
operation may have failed, if @{text f} may have failed or @{text g} may
have failed on any of the results of @{text f}.\<close>
definition bind ::
"('s, 'a) nondet_monad \<Rightarrow> ('a \<Rightarrow> ('s, 'b) nondet_monad) \<Rightarrow> ('s, 'b) nondet_monad"
(infixl ">>=" 60) where
"('s, 'a) nondet_monad \<Rightarrow> ('a \<Rightarrow> ('s, 'b) nondet_monad) \<Rightarrow> ('s, 'b) nondet_monad" (infixl ">>=" 60)
where
"bind f g \<equiv> \<lambda>s. (\<Union>(fst ` case_prod g ` fst (f s)),
True \<in> snd ` case_prod g ` fst (f s) \<or> snd (f s))"
text \<open>
Sometimes it is convenient to write @{text bind} in reverse order.\<close>
text \<open>Sometimes it is convenient to write @{text bind} in reverse order.\<close>
abbreviation (input) bind_rev ::
"('c \<Rightarrow> ('a, 'b) nondet_monad) \<Rightarrow> ('a, 'c) nondet_monad \<Rightarrow> ('a, 'b) nondet_monad"
(infixl "=<<" 60) where
"('c \<Rightarrow> ('a, 'b) nondet_monad) \<Rightarrow> ('a, 'c) nondet_monad \<Rightarrow> ('a, 'b) nondet_monad" (infixl "=<<" 60)
where
"g =<< f \<equiv> f >>= g"
text \<open>
@ -107,7 +106,8 @@ definition select :: "'a set \<Rightarrow> ('s,'a) nondet_monad" where
"select A \<equiv> \<lambda>s. (A \<times> {s}, False)"
definition alternative ::
"('s, 'a) nondet_monad \<Rightarrow> ('s, 'a) nondet_monad \<Rightarrow> ('s, 'a) nondet_monad" (infixl "\<sqinter>" 20) where
"('s, 'a) nondet_monad \<Rightarrow> ('s, 'a) nondet_monad \<Rightarrow> ('s, 'a) nondet_monad" (infixl "\<sqinter>" 20)
where
"f \<sqinter> g \<equiv> \<lambda>s. (fst (f s) \<union> fst (g s), snd (f s) \<or> snd (g s))"
text \<open>
@ -125,20 +125,21 @@ text \<open>
definition state_select :: "('s \<times> 's) set \<Rightarrow> ('s, unit) nondet_monad" where
"state_select r \<equiv> \<lambda>s. ((\<lambda>x. ((), x)) ` {s'. (s, s') \<in> r}, \<not> (\<exists>s'. (s, s') \<in> r))"
subsection "Failure"
text \<open>
The monad function that always fails. Returns an empty set of results and sets the failure flag.\<close>
definition fail :: "('s, 'a) nondet_monad" where
"fail \<equiv> \<lambda>s. ({}, True)"
"fail \<equiv> \<lambda>s. ({}, True)"
text \<open>Assertions: fail if the property @{text P} is not true\<close>
definition assert :: "bool \<Rightarrow> ('a, unit) nondet_monad" where
"assert P \<equiv> if P then return () else fail"
"assert P \<equiv> if P then return () else fail"
text \<open>Fail if the value is @{const None}, return result @{text v} for @{term "Some v"}\<close>
definition assert_opt :: "'a option \<Rightarrow> ('b, 'a) nondet_monad" where
"assert_opt v \<equiv> case v of None \<Rightarrow> fail | Some v \<Rightarrow> return v"
"assert_opt v \<equiv> case v of None \<Rightarrow> fail | Some v \<Rightarrow> return v"
text \<open>An assertion that also can introspect the current state.\<close>
definition state_assert :: "('s \<Rightarrow> bool) \<Rightarrow> ('s, unit) nondet_monad" where
@ -148,11 +149,11 @@ subsection "Generic functions on top of the state monad"
text \<open>Apply a function to the current state and return the result without changing the state.\<close>
definition gets :: "('s \<Rightarrow> 'a) \<Rightarrow> ('s, 'a) nondet_monad" where
"gets f \<equiv> get >>= (\<lambda>s. return (f s))"
"gets f \<equiv> get >>= (\<lambda>s. return (f s))"
text \<open>Modify the current state using the function passed in.\<close>
definition modify :: "('s \<Rightarrow> 's) \<Rightarrow> ('s, unit) nondet_monad" where
"modify f \<equiv> get >>= (\<lambda>s. put (f s))"
"modify f \<equiv> get >>= (\<lambda>s. put (f s))"
lemma simpler_gets_def:
"gets f = (\<lambda>s. ({(f s, s)}, False))"
@ -174,7 +175,8 @@ text \<open>
Perform a test on the current state, performing the left monad if
the result is true or the right monad if the result is false. \<close>
definition condition ::
"('s \<Rightarrow> bool) \<Rightarrow> ('s, 'r) nondet_monad \<Rightarrow> ('s, 'r) nondet_monad \<Rightarrow> ('s, 'r) nondet_monad" where
"('s \<Rightarrow> bool) \<Rightarrow> ('s, 'r) nondet_monad \<Rightarrow> ('s, 'r) nondet_monad \<Rightarrow> ('s, 'r) nondet_monad"
where
"condition P L R \<equiv> \<lambda>s. if (P s) then (L s) else (R s)"
notation (output)
@ -189,14 +191,13 @@ definition gets_the :: "('s \<Rightarrow> 'a option) \<Rightarrow> ('s, 'a) nond
text \<open>
Get a map (such as a heap) from the current state and apply an argument to the map.
Fail if the map returns @{const None}, otherwise return the value.\<close>
definition
gets_map :: "('s \<Rightarrow> 'a \<Rightarrow> 'b option) \<Rightarrow> 'a \<Rightarrow> ('s, 'b) nondet_monad" where
definition gets_map :: "('s \<Rightarrow> 'a \<Rightarrow> 'b option) \<Rightarrow> 'a \<Rightarrow> ('s, 'b) nondet_monad" where
"gets_map f p \<equiv> gets f >>= (\<lambda>m. assert_opt (m p))"
subsection \<open>The Monad Laws\<close>
text \<open>A more expanded definition of @{text bind}\<close>
text \<open>An alternative definition of @{term bind}, sometimes more convenient.\<close>
lemma bind_def':
"(f >>= g) \<equiv>
\<lambda>s. ({(r'', s''). \<exists>(r', s') \<in> fst (f s). (r'', s'') \<in> fst (g r' s') },
@ -212,7 +213,8 @@ lemma return_bind[simp]:
by (simp add: return_def bind_def)
text \<open>@{term return} is absorbed on the right of a @{term bind}\<close>
lemma bind_return[simp]: "(m >>= return) = m"
lemma bind_return[simp]:
"(m >>= return) = m"
by (simp add: bind_def return_def split_def)
text \<open>@{term bind} is associative\<close>
@ -264,7 +266,6 @@ definition bindE ::
(infixl ">>=E" 60) where
"f >>=E g \<equiv> f >>= lift g"
text \<open>
Lifting a normal nondeterministic monad into the
exception monad is achieved by always returning its
@ -272,7 +273,6 @@ text \<open>
definition liftE :: "('s,'a) nondet_monad \<Rightarrow> ('s, 'e+'a) nondet_monad" where
"liftE f \<equiv> f >>= (\<lambda>r. return (Inr r))"
text \<open>
Since the underlying type and @{text return} function changed,
we need new definitions for when and unless:\<close>
@ -282,13 +282,11 @@ definition whenE :: "bool \<Rightarrow> ('s, 'e + unit) nondet_monad \<Rightarro
definition unlessE :: "bool \<Rightarrow> ('s, 'e + unit) nondet_monad \<Rightarrow> ('s, 'e + unit) nondet_monad" where
"unlessE P f \<equiv> if P then returnOk () else f"
text \<open>
Throwing an exception when the parameter is @{term None}, otherwise
returning @{term "v"} for @{term "Some v"}.\<close>
definition throw_opt :: "'e \<Rightarrow> 'a option \<Rightarrow> ('s, 'e + 'a) nondet_monad" where
"throw_opt ex x \<equiv> case x of None \<Rightarrow> throwError ex | Some v \<Rightarrow> returnOk v"
"throw_opt ex x \<equiv> case x of None \<Rightarrow> throwError ex | Some v \<Rightarrow> returnOk v"
text \<open>
Failure in the exception monad is redefined in the same way
@ -297,6 +295,7 @@ text \<open>
definition assertE :: "bool \<Rightarrow> ('a, 'e + unit) nondet_monad" where
"assertE P \<equiv> if P then returnOk () else fail"
subsection "Monad Laws for the Exception Monad"
text \<open>More direct definition of @{const liftE}:\<close>
@ -415,9 +414,7 @@ lemma "doE x \<leftarrow> returnOk 1;
by simp
section "Library of Monadic Functions and Combinators"
section "Library of additional Monadic Functions and Combinators"
text \<open>Lifting a normal function into the monad type:\<close>
definition liftM :: "('a \<Rightarrow> 'b) \<Rightarrow> ('s,'a) nondet_monad \<Rightarrow> ('s, 'b) nondet_monad" where
@ -427,12 +424,11 @@ text \<open>The same for the exception monad:\<close>
definition liftME :: "('a \<Rightarrow> 'b) \<Rightarrow> ('s,'e+'a) nondet_monad \<Rightarrow> ('s,'e+'b) nondet_monad" where
"liftME f m \<equiv> doE x \<leftarrow> m; returnOk (f x) odE"
text \<open> Execute @{term f} for @{term "Some x"}, otherwise do nothing. \<close>
text \<open>Execute @{term f} for @{term "Some x"}, otherwise do nothing.\<close>
definition maybeM :: "('a \<Rightarrow> ('s, unit) nondet_monad) \<Rightarrow> 'a option \<Rightarrow> ('s, unit) nondet_monad" where
"maybeM f y \<equiv> case y of Some x \<Rightarrow> f x | None \<Rightarrow> return ()"
text \<open>
Run a sequence of monads from left to right, ignoring return values.\<close>
text \<open>Run a sequence of monads from left to right, ignoring return values.\<close>
definition sequence_x :: "('s, 'a) nondet_monad list \<Rightarrow> ('s, unit) nondet_monad" where
"sequence_x xs \<equiv> foldr (\<lambda>x y. x >>= (\<lambda>_. y)) xs (return ())"
@ -447,10 +443,10 @@ text \<open>
going through both lists simultaneously, left to right, ignoring
return values.\<close>
definition zipWithM_x ::
"('a \<Rightarrow> 'b \<Rightarrow> ('s,'c) nondet_monad) \<Rightarrow> 'a list \<Rightarrow> 'b list \<Rightarrow> ('s, unit) nondet_monad" where
"('a \<Rightarrow> 'b \<Rightarrow> ('s,'c) nondet_monad) \<Rightarrow> 'a list \<Rightarrow> 'b list \<Rightarrow> ('s, unit) nondet_monad"
where
"zipWithM_x f xs ys \<equiv> sequence_x (zipWith f xs ys)"
text \<open>
The same three functions as above, but returning a list of
return values instead of @{text unit}\<close>
@ -462,15 +458,18 @@ definition mapM :: "('a \<Rightarrow> ('s,'b) nondet_monad) \<Rightarrow> 'a lis
"mapM f xs \<equiv> sequence (map f xs)"
definition zipWithM ::
"('a \<Rightarrow> 'b \<Rightarrow> ('s,'c) nondet_monad) \<Rightarrow> 'a list \<Rightarrow> 'b list \<Rightarrow> ('s, 'c list) nondet_monad" where
"('a \<Rightarrow> 'b \<Rightarrow> ('s,'c) nondet_monad) \<Rightarrow> 'a list \<Rightarrow> 'b list \<Rightarrow> ('s, 'c list) nondet_monad"
where
"zipWithM f xs ys \<equiv> sequence (zipWith f xs ys)"
definition foldM :: "('b \<Rightarrow> 'a \<Rightarrow> ('s, 'a) nondet_monad) \<Rightarrow> 'b list \<Rightarrow> 'a \<Rightarrow> ('s, 'a) nondet_monad"
definition foldM ::
"('b \<Rightarrow> 'a \<Rightarrow> ('s, 'a) nondet_monad) \<Rightarrow> 'b list \<Rightarrow> 'a \<Rightarrow> ('s, 'a) nondet_monad"
where
"foldM m xs a \<equiv> foldr (\<lambda>p q. q >>= m p) xs (return a) "
definition foldME ::
"('b \<Rightarrow> 'a \<Rightarrow> ('s,('e + 'b)) nondet_monad) \<Rightarrow> 'b \<Rightarrow> 'a list \<Rightarrow> ('s, ('e + 'b)) nondet_monad" where
"('b \<Rightarrow> 'a \<Rightarrow> ('s,('e + 'b)) nondet_monad) \<Rightarrow> 'b \<Rightarrow> 'a list \<Rightarrow> ('s, ('e + 'b)) nondet_monad"
where
"foldME m a xs \<equiv> foldr (\<lambda>p q. q >>=E swp m p) xs (returnOk a)"
text \<open>
@ -486,11 +485,11 @@ definition sequenceE :: "('s, 'e+'a) nondet_monad list \<Rightarrow> ('s, 'e+'a
"sequenceE xs \<equiv> let mcons = (\<lambda>p q. p >>=E (\<lambda>x. q >>=E (\<lambda>y. returnOk (x#y))))
in foldr mcons xs (returnOk [])"
definition mapME :: "('a \<Rightarrow> ('s,'e+'b) nondet_monad) \<Rightarrow> 'a list \<Rightarrow> ('s,'e+'b list) nondet_monad"
definition mapME ::
"('a \<Rightarrow> ('s,'e+'b) nondet_monad) \<Rightarrow> 'a list \<Rightarrow> ('s,'e+'b list) nondet_monad"
where
"mapME f xs \<equiv> sequenceE (map f xs)"
text \<open>Filtering a list using a monadic function as predicate:\<close>
primrec filterM :: "('a \<Rightarrow> ('s, bool) nondet_monad) \<Rightarrow> 'a list \<Rightarrow> ('s, 'a list) nondet_monad" where
"filterM P [] = return []"
@ -536,8 +535,7 @@ text \<open>
The handler may throw a type of exceptions different from
the left side.\<close>
definition handleE' ::
"('s, 'e1 + 'a) nondet_monad \<Rightarrow> ('e1 \<Rightarrow> ('s, 'e2 + 'a) nondet_monad) \<Rightarrow>
('s, 'e2 + 'a) nondet_monad"
"('s, 'e1 + 'a) nondet_monad \<Rightarrow> ('e1 \<Rightarrow> ('s, 'e2 + 'a) nondet_monad) \<Rightarrow> ('s, 'e2 + 'a) nondet_monad"
(infix "<handle2>" 10) where
"f <handle2> handler \<equiv>
do
@ -556,15 +554,13 @@ definition handleE ::
(infix "<handle>" 10) where
"handleE \<equiv> handleE'"
text \<open>
Handling exceptions, and additionally providing a continuation
if the left-hand side throws no exception:\<close>
definition
handle_elseE ::
definition handle_elseE ::
"('s, 'e + 'a) nondet_monad \<Rightarrow> ('e \<Rightarrow> ('s, 'ee + 'b) nondet_monad) \<Rightarrow>
('a \<Rightarrow> ('s, 'ee + 'b) nondet_monad) \<Rightarrow> ('s, 'ee + 'b) nondet_monad"
("_ <handle> _ <else> _" 10) where
('a \<Rightarrow> ('s, 'ee + 'b) nondet_monad) \<Rightarrow> ('s, 'ee + 'b) nondet_monad" ("_ <handle> _ <else> _" 10)
where
"f <handle> handler <else> continue \<equiv>
do v \<leftarrow> f;
case v of Inl e \<Rightarrow> handler e
@ -593,7 +589,8 @@ inductive_simps whileLoop_results_simps_valid: "(Some x, Some y) \<in> whileLoop
inductive_simps whileLoop_results_simps_start_fail[simp]: "(None, x) \<in> whileLoop_results C B"
inductive whileLoop_terminates ::
"('r \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> ('r \<Rightarrow> ('s, 'r) nondet_monad) \<Rightarrow> 'r \<Rightarrow> 's \<Rightarrow> bool" for C B where
"('r \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> ('r \<Rightarrow> ('s, 'r) nondet_monad) \<Rightarrow> 'r \<Rightarrow> 's \<Rightarrow> bool"
for C B where
"\<not> C r s \<Longrightarrow> whileLoop_terminates C B r s"
| "\<lbrakk> C r s; \<forall>(r', s') \<in> fst (B r s). whileLoop_terminates C B r' s' \<rbrakk>
\<Longrightarrow> whileLoop_terminates C B r s"
@ -602,7 +599,8 @@ inductive_cases whileLoop_terminates_cases: "whileLoop_terminates C B r s"
inductive_simps whileLoop_terminates_simps: "whileLoop_terminates C B r s"
definition whileLoop ::
"('a \<Rightarrow> 'b \<Rightarrow> bool) \<Rightarrow> ('a \<Rightarrow> ('b, 'a) nondet_monad) \<Rightarrow> 'a \<Rightarrow> ('b, 'a) nondet_monad" where
"('a \<Rightarrow> 'b \<Rightarrow> bool) \<Rightarrow> ('a \<Rightarrow> ('b, 'a) nondet_monad) \<Rightarrow> 'a \<Rightarrow> ('b, 'a) nondet_monad"
where
"whileLoop C B \<equiv> \<lambda>r s.
({(r',s'). (Some (r, s), Some (r', s')) \<in> whileLoop_results C B},
(Some (r, s), None) \<in> whileLoop_results C B \<or> \<not>whileLoop_terminates C B r s)"
@ -626,7 +624,8 @@ definition notM :: "('s, bool) nondet_monad \<Rightarrow> ('s, bool) nondet_mona
"notM m = do c \<leftarrow> m; return (\<not> c) od"
definition whileM ::
"('s, bool) nondet_monad \<Rightarrow> ('s, 'a) nondet_monad \<Rightarrow> ('s, unit) nondet_monad" where
"('s, bool) nondet_monad \<Rightarrow> ('s, 'a) nondet_monad \<Rightarrow> ('s, unit) nondet_monad"
where
"whileM C B \<equiv> do
c \<leftarrow> C;
whileLoop (\<lambda>c s. c) (\<lambda>_. do B; C od) c;
@ -634,8 +633,8 @@ definition whileM ::
od"
definition ifM ::
"('s, bool) nondet_monad \<Rightarrow> ('s, 'a) nondet_monad \<Rightarrow> ('s, 'a) nondet_monad \<Rightarrow>
('s, 'a) nondet_monad" where
"('s, bool) nondet_monad \<Rightarrow> ('s, 'a) nondet_monad \<Rightarrow> ('s, 'a) nondet_monad \<Rightarrow> ('s, 'a) nondet_monad"
where
"ifM test t f = do
c \<leftarrow> test;
if c then t else f
@ -643,22 +642,26 @@ definition ifM ::
definition ifME ::
"('a, 'b + bool) nondet_monad \<Rightarrow> ('a, 'b + 'c) nondet_monad \<Rightarrow> ('a, 'b + 'c) nondet_monad
\<Rightarrow> ('a, 'b + 'c) nondet_monad" where
\<Rightarrow> ('a, 'b + 'c) nondet_monad"
where
"ifME test t f = doE
c \<leftarrow> test;
if c then t else f
odE"
definition whenM ::
"('s, bool) nondet_monad \<Rightarrow> ('s, unit) nondet_monad \<Rightarrow> ('s, unit) nondet_monad" where
"('s, bool) nondet_monad \<Rightarrow> ('s, unit) nondet_monad \<Rightarrow> ('s, unit) nondet_monad"
where
"whenM t m = ifM t m (return ())"
definition orM ::
"('s, bool) nondet_monad \<Rightarrow> ('s, bool) nondet_monad \<Rightarrow> ('s, bool) nondet_monad" where
"('s, bool) nondet_monad \<Rightarrow> ('s, bool) nondet_monad \<Rightarrow> ('s, bool) nondet_monad"
where
"orM a b = ifM a (return True) b"
definition andM ::
"('s, bool) nondet_monad \<Rightarrow> ('s, bool) nondet_monad \<Rightarrow> ('s, bool) nondet_monad" where
"('s, bool) nondet_monad \<Rightarrow> ('s, bool) nondet_monad \<Rightarrow> ('s, bool) nondet_monad"
where
"andM a b = ifM a b (return False)"
end

View File

@ -160,7 +160,7 @@ lemma no_fail_spec:
lemma no_fail_assertE[wp]:
"no_fail (\<lambda>_. P) (assertE P)"
by (simp add: assertE_def split: if_split)
by (simp add: assertE_def)
lemma no_fail_spec_pre:
"\<lbrakk> no_fail (((=) s) and P') f; \<And>s. P s \<Longrightarrow> P' s \<rbrakk> \<Longrightarrow> no_fail (((=) s) and P) f"
@ -168,7 +168,7 @@ lemma no_fail_spec_pre:
lemma no_fail_whenE[wp]:
"\<lbrakk> G \<Longrightarrow> no_fail P f \<rbrakk> \<Longrightarrow> no_fail (\<lambda>s. G \<longrightarrow> P s) (whenE G f)"
by (simp add: whenE_def split: if_split)
by (simp add: whenE_def)
lemma no_fail_unlessE[wp]:
"\<lbrakk> \<not> G \<Longrightarrow> no_fail P f \<rbrakk> \<Longrightarrow> no_fail (\<lambda>s. \<not> G \<longrightarrow> P s) (unlessE G f)"

View File

@ -17,7 +17,8 @@ text \<open>
The dual to validity: an existential instead of a universal quantifier for the post condition.
In refinement, it is often sufficient to know that there is one state that satisfies a condition.\<close>
definition exs_valid ::
"('a \<Rightarrow> bool) \<Rightarrow> ('a, 'b) nondet_monad \<Rightarrow> ('b \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> bool" ("\<lbrace>_\<rbrace> _ \<exists>\<lbrace>_\<rbrace>") where
"('a \<Rightarrow> bool) \<Rightarrow> ('a, 'b) nondet_monad \<Rightarrow> ('b \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> bool"
("\<lbrace>_\<rbrace> _ \<exists>\<lbrace>_\<rbrace>") where
"\<lbrace>P\<rbrace> f \<exists>\<lbrace>Q\<rbrace> \<equiv> \<forall>s. P s \<longrightarrow> (\<exists>(rv, s') \<in> fst (f s). Q rv s')"
text \<open>The above for the exception monad\<close>

View File

@ -20,7 +20,8 @@ text \<open>
is often similar. The following definitions allow such reasoning to take place.\<close>
definition validNF ::
"('s \<Rightarrow> bool) \<Rightarrow> ('s,'a) nondet_monad \<Rightarrow> ('a \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> bool" ("\<lbrace>_\<rbrace>/ _ /\<lbrace>_\<rbrace>!") where
"('s \<Rightarrow> bool) \<Rightarrow> ('s,'a) nondet_monad \<Rightarrow> ('a \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> bool"
("\<lbrace>_\<rbrace>/ _ /\<lbrace>_\<rbrace>!") where
"\<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace>! \<equiv> \<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace> \<and> no_fail P f"
lemma validNF_alt_def:
@ -304,7 +305,8 @@ lemma validNF_nobindE[wp]:
text \<open>
Set up triple rules for @{term validE_NF} so that we can use @{method wp} combinator rules.\<close>
definition validE_NF_property ::
"('a \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> ('c \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> 's \<Rightarrow> ('s, 'c+'a) nondet_monad \<Rightarrow> bool" where
"('a \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> ('c \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> 's \<Rightarrow> ('s, 'c+'a) nondet_monad \<Rightarrow> bool"
where
"validE_NF_property Q E s b \<equiv>
\<not> snd (b s) \<and> (\<forall>(r', s') \<in> fst (b s). case r' of Inl x \<Rightarrow> E x s' | Inr x \<Rightarrow> Q x s')"

View File

@ -35,14 +35,16 @@ text \<open>
to assume @{term P}! Proving non-failure is done via a separate predicate and
calculus (see Nondet_No_Fail).\<close>
definition valid ::
"('s \<Rightarrow> bool) \<Rightarrow> ('s,'a) nondet_monad \<Rightarrow> ('a \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> bool" ("\<lbrace>_\<rbrace>/ _ /\<lbrace>_\<rbrace>") where
"('s \<Rightarrow> bool) \<Rightarrow> ('s,'a) nondet_monad \<Rightarrow> ('a \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> bool"
("\<lbrace>_\<rbrace>/ _ /\<lbrace>_\<rbrace>") where
"\<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace> \<equiv> \<forall>s. P s \<longrightarrow> (\<forall>(r,s') \<in> fst (f s). Q r s')"
text \<open>
We often reason about invariant predicates. The following provides shorthand syntax
that avoids repeating potentially long predicates.\<close>
abbreviation (input) invariant ::
"('s,'a) nondet_monad \<Rightarrow> ('s \<Rightarrow> bool) \<Rightarrow> bool" ("_ \<lbrace>_\<rbrace>" [59,0] 60) where
"('s,'a) nondet_monad \<Rightarrow> ('s \<Rightarrow> bool) \<Rightarrow> bool"
("_ \<lbrace>_\<rbrace>" [59,0] 60) where
"invariant f P \<equiv> \<lbrace>P\<rbrace> f \<lbrace>\<lambda>_. P\<rbrace>"
text \<open>
@ -708,7 +710,7 @@ lemma hoare_vcg_if_lift:
by (auto simp: valid_def split_def)
lemma hoare_vcg_disj_lift_R:
assumes x: "\<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace>,-"
assumes x: "\<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace>,-"
assumes y: "\<lbrace>P'\<rbrace> f \<lbrace>Q'\<rbrace>,-"
shows "\<lbrace>\<lambda>s. P s \<or> P' s\<rbrace> f \<lbrace>\<lambda>rv s. Q rv s \<or> Q' rv s\<rbrace>,-"
using assms

View File

@ -47,12 +47,14 @@ text \<open>
\<close>
definition whileLoop_inv ::
"('a \<Rightarrow> 'b \<Rightarrow> bool) \<Rightarrow> ('a \<Rightarrow> ('b, 'a) nondet_monad) \<Rightarrow> 'a \<Rightarrow> ('a \<Rightarrow> 'b \<Rightarrow> bool) \<Rightarrow>
(('a \<times> 'b) \<times> 'a \<times> 'b) set \<Rightarrow> ('b, 'a) nondet_monad" where
(('a \<times> 'b) \<times> 'a \<times> 'b) set \<Rightarrow> ('b, 'a) nondet_monad"
where
"whileLoop_inv C B x I R \<equiv> whileLoop C B x"
definition whileLoopE_inv ::
"('a \<Rightarrow> 'b \<Rightarrow> bool) \<Rightarrow> ('a \<Rightarrow> ('b, 'c + 'a) nondet_monad) \<Rightarrow> 'a \<Rightarrow> ('a \<Rightarrow> 'b \<Rightarrow> bool) \<Rightarrow>
(('a \<times> 'b) \<times> 'a \<times> 'b) set \<Rightarrow> ('b, 'c + 'a) nondet_monad" where
(('a \<times> 'b) \<times> 'a \<times> 'b) set \<Rightarrow> ('b, 'c + 'a) nondet_monad"
where
"whileLoopE_inv C B x I R \<equiv> whileLoopE C B x"
lemma whileLoop_add_inv:
@ -287,7 +289,7 @@ lemma fst_whileLoop_cond_false:
lemma snd_whileLoop:
assumes init_I: "I r s"
and cond_I: "C r s"
and non_term: "\<And>r. \<lbrace> \<lambda>s. I r s \<and> C r s \<and> \<not> snd (B r s) \<rbrace> B r \<exists>\<lbrace> \<lambda>r' s'. C r' s' \<and> I r' s' \<rbrace>"
and non_term: "\<And>r. \<lbrace> \<lambda>s. I r s \<and> C r s \<and> \<not> snd (B r s) \<rbrace> B r \<exists>\<lbrace> \<lambda>r' s'. C r' s' \<and> I r' s' \<rbrace>"
shows "snd (whileLoop C B r s)"
apply (clarsimp simp: whileLoop_def)
apply (rotate_tac)

View File

@ -38,14 +38,13 @@ datatype ('s, 'a) tmres = Failed | Incomplete | Result "('a \<times> 's)"
abbreviation map_tmres_rv :: "('a \<Rightarrow> 'b) \<Rightarrow> ('s, 'a) tmres \<Rightarrow> ('s, 'b) tmres" where
"map_tmres_rv f \<equiv> map_tmres id f"
section "The Monad"
text \<open>
tmonad returns a set of non-deterministic computations, including
a trace as a list of "thread identifier" \<times> state, and an optional
pair of result and state when the computation did not fail.\<close>
type_synonym ('s, 'a) tmonad = "'s \<Rightarrow> ((tmid \<times> 's) list \<times> ('s, 'a) tmres) set"
text \<open>
Print the type @{typ "('s,'a) tmonad"} instead of its unwieldy expansion.
Needs an AST translation in code, because it needs to check that the state variable
@ -64,6 +63,7 @@ print_ast_translation \<open>
else raise Match
in [(@{type_syntax "fun"}, tmonad_tr)] end\<close>
text \<open>Returns monad results, ignoring failures and traces.\<close>
definition mres :: "((tmid \<times> 's) list \<times> ('s, 'a) tmres) set \<Rightarrow> ('a \<times> 's) set" where
"mres r = Result -` (snd ` r)"
@ -98,7 +98,7 @@ definition bind ::
| Result (rv, s) \<Rightarrow> fst_upd (\<lambda>ys. ys @ xs) ` g rv s"
text \<open>Sometimes it is convenient to write @{text bind} in reverse order.\<close>
abbreviation(input) bind_rev ::
abbreviation (input) bind_rev ::
"('c \<Rightarrow> ('a, 'b) tmonad) \<Rightarrow> ('a, 'c) tmonad \<Rightarrow> ('a, 'b) tmonad" (infixl "=<<" 60)
where
"g =<< f \<equiv> f >>= g"
@ -123,6 +123,7 @@ primrec put_trace :: "(tmid \<times> 's) list \<Rightarrow> ('s, unit) tmonad" w
"put_trace [] = return ()"
| "put_trace (x # xs) = (put_trace xs >>= (\<lambda>_. put_trace_elem x))"
subsection "Nondeterminism"
text \<open>
@ -134,8 +135,9 @@ text \<open>
definition select :: "'a set \<Rightarrow> ('s, 'a) tmonad" where
"select A \<equiv> \<lambda>s. (Pair [] ` Result ` (A \<times> {s}))"
definition alternative :: "('s,'a) tmonad \<Rightarrow> ('s,'a) tmonad \<Rightarrow> ('s,'a) tmonad"
(infixl "\<sqinter>" 20) where
definition alternative ::
"('s,'a) tmonad \<Rightarrow> ('s,'a) tmonad \<Rightarrow> ('s,'a) tmonad" (infixl "\<sqinter>" 20)
where
"f \<sqinter> g \<equiv> \<lambda>s. (f s \<union> g s)"
text \<open>
@ -153,6 +155,7 @@ definition state_select :: "('s \<times> 's) set \<Rightarrow> ('s, unit) tmonad
"state_select r \<equiv>
\<lambda>s. (Pair [] ` default_elem Failed (Result ` (\<lambda>x. ((), x)) ` {s'. (s, s') \<in> r}))"
subsection "Failure"
text \<open>
@ -202,7 +205,8 @@ text \<open>
Perform a test on the current state, performing the left monad if
the result is true or the right monad if the result is false.\<close>
definition condition ::
"('s \<Rightarrow> bool) \<Rightarrow> ('s, 'r) tmonad \<Rightarrow> ('s, 'r) tmonad \<Rightarrow> ('s, 'r) tmonad" where
"('s \<Rightarrow> bool) \<Rightarrow> ('s, 'r) tmonad \<Rightarrow> ('s, 'r) tmonad \<Rightarrow> ('s, 'r) tmonad"
where
"condition P L R \<equiv> \<lambda>s. if (P s) then (L s) else (R s)"
notation (output)
@ -217,15 +221,14 @@ definition gets_the :: "('s \<Rightarrow> 'a option) \<Rightarrow> ('s, 'a) tmon
text \<open>
Get a map (such as a heap) from the current state and apply an argument to the map.
Fail if the map returns @{const None}, otherwise return the value.\<close>
definition
gets_map :: "('s \<Rightarrow> 'a \<Rightarrow> 'b option) \<Rightarrow> 'a \<Rightarrow> ('s, 'b) tmonad" where
definition gets_map :: "('s \<Rightarrow> 'a \<Rightarrow> 'b option) \<Rightarrow> 'a \<Rightarrow> ('s, 'b) tmonad" where
"gets_map f p \<equiv> gets f >>= (\<lambda>m. assert_opt (m p))"
subsection \<open>The Monad Laws\<close>
text \<open>An alternative definition of bind, sometimes more convenient.\<close>
lemma bind_def2:
text \<open>An alternative definition of @{term bind}, sometimes more convenient.\<close>
lemma bind_def':
"bind f g \<equiv>
\<lambda>s. ((\<lambda>xs. (xs, Failed)) ` {xs. (xs, Failed) \<in> f s})
\<union> ((\<lambda>xs. (xs, Incomplete)) ` {xs. (xs, Incomplete) \<in> f s})
@ -242,7 +245,7 @@ lemma elem_bindE:
\<lbrakk>res = Incomplete \<or> res = Failed; (tr, map_tmres undefined undefined res) \<in> f s\<rbrakk> \<Longrightarrow> P;
\<And>tr' tr'' x s'. \<lbrakk>(tr', Result (x, s')) \<in> f s; (tr'', res) \<in> g x s'; tr = tr'' @ tr'\<rbrakk> \<Longrightarrow> P\<rbrakk>
\<Longrightarrow> P"
by (auto simp: bind_def2)
by (auto simp: bind_def')
text \<open>Each monad satisfies at least the following three laws.\<close>
@ -277,6 +280,7 @@ lemma bind_assoc:
apply (simp add: image_image)
done
section \<open>Adding Exceptions\<close>
text \<open>
@ -312,8 +316,8 @@ text \<open>
the right-hand side is skipped if the left-hand side
produced an exception.\<close>
definition bindE ::
"('s, 'e + 'a) tmonad \<Rightarrow> ('a \<Rightarrow> ('s, 'e + 'b) tmonad) \<Rightarrow> ('s, 'e + 'b) tmonad"
(infixl ">>=E" 60) where
"('s, 'e + 'a) tmonad \<Rightarrow> ('a \<Rightarrow> ('s, 'e + 'b) tmonad) \<Rightarrow> ('s, 'e + 'b) tmonad" (infixl ">>=E" 60)
where
"f >>=E g \<equiv> f >>= lift g"
text \<open>
@ -345,6 +349,7 @@ text \<open>
definition assertE :: "bool \<Rightarrow> ('a, 'e + unit) tmonad" where
"assertE P \<equiv> if P then returnOk () else fail"
subsection "Monad Laws for the Exception Monad"
text \<open>More direct definition of @{const liftE}:\<close>
@ -545,7 +550,8 @@ text \<open>
going through both lists simultaneously, left to right, ignoring
return values.\<close>
definition zipWithM_x ::
"('a \<Rightarrow> 'b \<Rightarrow> ('s,'c) tmonad) \<Rightarrow> 'a list \<Rightarrow> 'b list \<Rightarrow> ('s, unit) tmonad" where
"('a \<Rightarrow> 'b \<Rightarrow> ('s,'c) tmonad) \<Rightarrow> 'a list \<Rightarrow> 'b list \<Rightarrow> ('s, unit) tmonad"
where
"zipWithM_x f xs ys \<equiv> sequence_x (zipWith f xs ys)"
text \<open>
@ -559,14 +565,16 @@ definition mapM :: "('a \<Rightarrow> ('s,'b) tmonad) \<Rightarrow> 'a list \<Ri
"mapM f xs \<equiv> sequence (map f xs)"
definition zipWithM ::
"('a \<Rightarrow> 'b \<Rightarrow> ('s,'c) tmonad) \<Rightarrow> 'a list \<Rightarrow> 'b list \<Rightarrow> ('s, 'c list) tmonad" where
"('a \<Rightarrow> 'b \<Rightarrow> ('s,'c) tmonad) \<Rightarrow> 'a list \<Rightarrow> 'b list \<Rightarrow> ('s, 'c list) tmonad"
where
"zipWithM f xs ys \<equiv> sequence (zipWith f xs ys)"
definition foldM :: "('b \<Rightarrow> 'a \<Rightarrow> ('s, 'a) tmonad) \<Rightarrow> 'b list \<Rightarrow> 'a \<Rightarrow> ('s, 'a) tmonad" where
"foldM m xs a \<equiv> foldr (\<lambda>p q. q >>= m p) xs (return a) "
definition foldME ::
"('b \<Rightarrow> 'a \<Rightarrow> ('s,('e + 'b)) tmonad) \<Rightarrow> 'b \<Rightarrow> 'a list \<Rightarrow> ('s, ('e + 'b)) tmonad" where
"('b \<Rightarrow> 'a \<Rightarrow> ('s,('e + 'b)) tmonad) \<Rightarrow> 'b \<Rightarrow> 'a list \<Rightarrow> ('s, ('e + 'b)) tmonad"
where
"foldME m a xs \<equiv> foldr (\<lambda>p q. q >>=E swp m p) xs (returnOk a)"
text \<open>
@ -585,7 +593,6 @@ definition sequenceE :: "('s, 'e+'a) tmonad list \<Rightarrow> ('s, 'e+'a list)
definition mapME :: "('a \<Rightarrow> ('s,'e+'b) tmonad) \<Rightarrow> 'a list \<Rightarrow> ('s,'e+'b list) tmonad" where
"mapME f xs \<equiv> sequenceE (map f xs)"
text \<open>Filtering a list using a monadic function as predicate:\<close>
primrec filterM :: "('a \<Rightarrow> ('s, bool) tmonad) \<Rightarrow> 'a list \<Rightarrow> ('s, 'a list) tmonad" where
"filterM P [] = return []"
@ -617,7 +624,8 @@ text \<open>
Turning an exception monad into a normal state monad
by catching and handling any potential exceptions:\<close>
definition catch ::
"('s, 'e + 'a) tmonad \<Rightarrow> ('e \<Rightarrow> ('s, 'a) tmonad) \<Rightarrow> ('s, 'a) tmonad" (infix "<catch>" 10) where
"('s, 'e + 'a) tmonad \<Rightarrow> ('e \<Rightarrow> ('s, 'a) tmonad) \<Rightarrow> ('s, 'a) tmonad" (infix "<catch>" 10)
where
"f <catch> handler \<equiv>
do x \<leftarrow> f;
case x of
@ -645,8 +653,8 @@ text \<open>
practice: the exception handle (potentially) throws exception
of the same type as the left-hand side.\<close>
definition handleE ::
"('s, 'x + 'a) tmonad \<Rightarrow> ('x \<Rightarrow> ('s, 'x + 'a) tmonad) \<Rightarrow> ('s, 'x + 'a) tmonad"
(infix "<handle>" 10) where
"('s, 'x + 'a) tmonad \<Rightarrow> ('x \<Rightarrow> ('s, 'x + 'a) tmonad) \<Rightarrow> ('s, 'x + 'a) tmonad" (infix "<handle>" 10)
where
"handleE \<equiv> handleE'"
text \<open>
@ -654,8 +662,8 @@ text \<open>
if the left-hand side throws no exception:\<close>
definition handle_elseE ::
"('s, 'e + 'a) tmonad \<Rightarrow> ('e \<Rightarrow> ('s, 'ee + 'b) tmonad) \<Rightarrow> ('a \<Rightarrow> ('s, 'ee + 'b) tmonad) \<Rightarrow>
('s, 'ee + 'b) tmonad"
("_ <handle> _ <else> _" 10) where
('s, 'ee + 'b) tmonad" ("_ <handle> _ <else> _" 10)
where
"f <handle> handler <else> continue \<equiv>
do v \<leftarrow> f;
case v of Inl e \<Rightarrow> handler e
@ -698,7 +706,8 @@ inductive_cases whileLoop_terminates_cases: "whileLoop_terminates C B r s"
inductive_simps whileLoop_terminates_simps: "whileLoop_terminates C B r s"
definition whileLoop ::
"('r \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> ('r \<Rightarrow> ('s, 'r) tmonad) \<Rightarrow> 'r \<Rightarrow> ('s, 'r) tmonad" where
"('r \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> ('r \<Rightarrow> ('s, 'r) tmonad) \<Rightarrow> 'r \<Rightarrow> ('s, 'r) tmonad"
where
"whileLoop C B \<equiv> (\<lambda>r s. {(ts, res). ((r,s), ts,res) \<in> whileLoop_results C B})"
notation (output)
@ -706,7 +715,8 @@ notation (output)
\<comment> \<open>FIXME: why does this differ to Nondet_Monad?\<close>
definition whileLoopT ::
"('r \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> ('r \<Rightarrow> ('s, 'r) tmonad) \<Rightarrow> 'r \<Rightarrow> ('s, 'r) tmonad" where
"('r \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> ('r \<Rightarrow> ('s, 'r) tmonad) \<Rightarrow> 'r \<Rightarrow> ('s, 'r) tmonad"
where
"whileLoopT C B \<equiv> (\<lambda>r s. {(ts, res). ((r,s), ts,res) \<in> whileLoop_results C B
\<and> whileLoop_terminates C B r s})"
@ -714,7 +724,8 @@ notation (output)
whileLoopT ("(whileLoopT (_)// (_))" [1000, 1000] 1000)
definition whileLoopE ::
"('r \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> ('r \<Rightarrow> ('s, 'e + 'r) tmonad) \<Rightarrow> 'r \<Rightarrow> ('s, ('e + 'r)) tmonad" where
"('r \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> ('r \<Rightarrow> ('s, 'e + 'r) tmonad) \<Rightarrow> 'r \<Rightarrow> ('s, ('e + 'r)) tmonad"
where
"whileLoopE C body \<equiv>
\<lambda>r. whileLoop (\<lambda>r s. (case r of Inr v \<Rightarrow> C v s | _ \<Rightarrow> False)) (lift body) (Inr r)"
@ -727,44 +738,38 @@ section "Combinators that have conditions with side effects"
definition notM :: "('s, bool) tmonad \<Rightarrow> ('s, bool) tmonad" where
"notM m = do c \<leftarrow> m; return (\<not> c) od"
definition whileM ::
"('s, bool) tmonad \<Rightarrow> ('s, 'a) tmonad \<Rightarrow> ('s, unit) tmonad" where
definition whileM :: "('s, bool) tmonad \<Rightarrow> ('s, 'a) tmonad \<Rightarrow> ('s, unit) tmonad" where
"whileM C B \<equiv> do
c \<leftarrow> C;
whileLoop (\<lambda>c s. c) (\<lambda>_. do B; C od) c;
return ()
od"
definition ifM ::
"('s, bool) tmonad \<Rightarrow> ('s, 'a) tmonad \<Rightarrow> ('s, 'a) tmonad \<Rightarrow>
('s, 'a) tmonad" where
definition ifM :: "('s, bool) tmonad \<Rightarrow> ('s, 'a) tmonad \<Rightarrow> ('s, 'a) tmonad \<Rightarrow> ('s, 'a) tmonad" where
"ifM test t f = do
c \<leftarrow> test;
if c then t else f
od"
definition ifME ::
"('a, 'b + bool) tmonad \<Rightarrow> ('a, 'b + 'c) tmonad \<Rightarrow> ('a, 'b + 'c) tmonad
\<Rightarrow> ('a, 'b + 'c) tmonad" where
"('a, 'b + bool) tmonad \<Rightarrow> ('a, 'b + 'c) tmonad \<Rightarrow> ('a, 'b + 'c) tmonad \<Rightarrow> ('a, 'b + 'c) tmonad"
where
"ifME test t f = doE
c \<leftarrow> test;
if c then t else f
odE"
definition whenM ::
"('s, bool) tmonad \<Rightarrow> ('s, unit) tmonad \<Rightarrow> ('s, unit) tmonad" where
definition whenM :: "('s, bool) tmonad \<Rightarrow> ('s, unit) tmonad \<Rightarrow> ('s, unit) tmonad" where
"whenM t m = ifM t m (return ())"
definition orM ::
"('s, bool) tmonad \<Rightarrow> ('s, bool) tmonad \<Rightarrow> ('s, bool) tmonad" where
definition orM :: "('s, bool) tmonad \<Rightarrow> ('s, bool) tmonad \<Rightarrow> ('s, bool) tmonad" where
"orM a b = ifM a (return True) b"
definition
andM :: "('s, bool) tmonad \<Rightarrow> ('s, bool) tmonad \<Rightarrow> ('s, bool) tmonad" where
definition andM :: "('s, bool) tmonad \<Rightarrow> ('s, bool) tmonad \<Rightarrow> ('s, bool) tmonad" where
"andM a b = ifM a b (return False)"
subsection "Await command"
section "Await command"
text \<open>@{term "Await c f"} blocks the execution until @{term "c"} is true,
and then atomically executes @{term "f"}.\<close>
@ -782,7 +787,7 @@ definition Await :: "('s \<Rightarrow> bool) \<Rightarrow> ('s,unit) tmonad" whe
od"
section "Trace monad Parallel"
section "Parallel combinator"
definition parallel :: "('s,'a) tmonad \<Rightarrow> ('s,'a) tmonad \<Rightarrow> ('s,'a) tmonad" where
"parallel f g = (\<lambda>s. {(xs, rv). \<exists>f_steps. length f_steps = length xs

View File

@ -286,6 +286,14 @@ lemma gets_fold_into_modify:
by (simp_all add: fun_eq_iff modify_def bind_assoc exec_gets
exec_get exec_put)
lemma gets_return_gets_eq:
"gets f >>= (\<lambda>g. return (h g)) = gets (\<lambda>s. h (f s))"
by (simp add: simpler_gets_def bind_def return_def)
lemma gets_prod_comp:
"gets (case x of (a, b) \<Rightarrow> f a b) = (case x of (a, b) \<Rightarrow> gets (f a b))"
by (auto simp: split_def)
lemma bind_assoc2:
"(do x \<leftarrow> a; _ \<leftarrow> b; c x od) = (do x \<leftarrow> (do x' \<leftarrow> a; _ \<leftarrow> b; return x' od); c x od)"
by (simp add: bind_assoc)

View File

@ -45,14 +45,6 @@ lemma hoare_name_pre_stateE:
"\<lbrakk>\<And>s. P s \<Longrightarrow> \<lbrace>(=) s\<rbrace> f \<lbrace>Q\<rbrace>, \<lbrace>E\<rbrace>\<rbrakk> \<Longrightarrow> \<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace>, \<lbrace>E\<rbrace>"
by (clarsimp simp: validE_def2)
lemma hoare_vcg_if_lift:
"\<lbrace>R\<rbrace> f \<lbrace>\<lambda>rv s. (P \<longrightarrow> X rv s) \<and> (\<not>P \<longrightarrow> Y rv s)\<rbrace> \<Longrightarrow>
\<lbrace>R\<rbrace> f \<lbrace>\<lambda>rv s. if P then X rv s else Y rv s\<rbrace>"
"\<lbrace>R\<rbrace> f \<lbrace>\<lambda>rv s. (P \<longrightarrow> X rv s) \<and> (\<not>P \<longrightarrow> Y rv s)\<rbrace> \<Longrightarrow>
\<lbrace>R\<rbrace> f \<lbrace>\<lambda>rv. if P then X rv else Y rv\<rbrace>"
by (auto simp: valid_def split_def)
lemma hoare_vcg_if_lift_strong:
"\<lbrakk> \<lbrace>P'\<rbrace> f \<lbrace>P\<rbrace>; \<lbrace>\<lambda>s. \<not> P' s\<rbrace> f \<lbrace>\<lambda>rv s. \<not> P rv s\<rbrace>; \<lbrace>Q'\<rbrace> f \<lbrace>Q\<rbrace>; \<lbrace>R'\<rbrace> f \<lbrace>R\<rbrace> \<rbrakk> \<Longrightarrow>
\<lbrace>\<lambda>s. if P' s then Q' s else R' s\<rbrace> f \<lbrace>\<lambda>rv s. if P rv s then Q rv s else R rv s\<rbrace>"
@ -240,13 +232,6 @@ lemma hoare_vcg_if_lift_ER: (* Required because of lack of rv in lifting rules *
\<lbrace>R\<rbrace> f \<lbrace>\<lambda>rv. if P' rv then X rv else Y rv\<rbrace>, -"
by (auto simp: valid_def validE_R_def validE_def split_def)
lemma hoare_vcg_imp_liftE:
"\<lbrakk> \<lbrace>P'\<rbrace> f \<lbrace>\<lambda>rv s. \<not> P rv s\<rbrace>, \<lbrace>A\<rbrace>; \<lbrace>Q'\<rbrace> f \<lbrace>Q\<rbrace>, \<lbrace>A\<rbrace> \<rbrakk>
\<Longrightarrow> \<lbrace>\<lambda>s. \<not> P' s \<longrightarrow> Q' s\<rbrace> f \<lbrace>\<lambda>rv s. P rv s \<longrightarrow> Q rv s\<rbrace>, \<lbrace>A\<rbrace>"
apply (simp only: imp_conv_disj)
apply (clarsimp simp: validE_def valid_def split_def sum.case_eq_if)
done
lemma hoare_list_all_lift:
"(\<And>r. r \<in> set xs \<Longrightarrow> \<lbrace>Q r\<rbrace> f \<lbrace>\<lambda>rv. Q r\<rbrace>)
\<Longrightarrow> \<lbrace>\<lambda>s. list_all (\<lambda>r. Q r s) xs\<rbrace> f \<lbrace>\<lambda>rv s. list_all (\<lambda>r. Q r s) xs\<rbrace>"
@ -394,13 +379,6 @@ lemma hoare_validE_R_conj:
"\<lbrakk>\<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace>, -; \<lbrace>P\<rbrace> f \<lbrace>R\<rbrace>, -\<rbrakk> \<Longrightarrow> \<lbrace>P\<rbrace> f \<lbrace>Q and R\<rbrace>, -"
by (simp add: valid_def validE_def validE_R_def Let_def split_def split: sum.splits)
lemma hoare_vcg_disj_lift_R:
assumes x: "\<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace>,-"
assumes y: "\<lbrace>P'\<rbrace> f \<lbrace>Q'\<rbrace>,-"
shows "\<lbrace>\<lambda>s. P s \<or> P' s\<rbrace> f \<lbrace>\<lambda>rv s. Q rv s \<or> Q' rv s\<rbrace>,-"
using assms
by (fastforce simp: validE_R_def validE_def valid_def split: sum.splits)
lemmas throwError_validE_R = throwError_wp [where E="\<top>\<top>", folded validE_R_def]
lemma valid_case_option_post_wp:
@ -552,10 +530,6 @@ lemma wp_split_const_if_R:
shows "\<lbrace>\<lambda>s. (G \<longrightarrow> P s) \<and> (\<not> G \<longrightarrow> P' s)\<rbrace> f \<lbrace>\<lambda>rv s. (G \<longrightarrow> Q rv s) \<and> (\<not> G \<longrightarrow> Q' rv s)\<rbrace>,-"
by (case_tac G, simp_all add: x y)
lemma hoare_vcg_imp_lift_R:
"\<lbrakk> \<lbrace>P'\<rbrace> f \<lbrace>\<lambda>rv s. \<not> P rv s\<rbrace>, -; \<lbrace>Q'\<rbrace> f \<lbrace>Q\<rbrace>, - \<rbrakk> \<Longrightarrow> \<lbrace>\<lambda>s. P' s \<or> Q' s\<rbrace> f \<lbrace>\<lambda>rv s. P rv s \<longrightarrow> Q rv s\<rbrace>, -"
by (auto simp add: valid_def validE_R_def validE_def split_def split: sum.splits)
lemma hoare_disj_division:
"\<lbrakk> P \<or> Q; P \<Longrightarrow> \<lbrace>R\<rbrace> f \<lbrace>S\<rbrace>; Q \<Longrightarrow> \<lbrace>T\<rbrace> f \<lbrace>S\<rbrace> \<rbrakk>
\<Longrightarrow> \<lbrace>\<lambda>s. (P \<longrightarrow> R s) \<and> (Q \<longrightarrow> T s)\<rbrace> f \<lbrace>S\<rbrace>"

View File

@ -131,7 +131,7 @@ lemma no_fail_returnOK[simp, wp]:
lemma no_fail_bind[wp]:
"\<lbrakk> no_fail P f; \<And>x. no_fail (R x) (g x); \<lbrace>Q\<rbrace> f \<lbrace>R\<rbrace> \<rbrakk> \<Longrightarrow> no_fail (P and Q) (f >>= (\<lambda>rv. g rv))"
apply (simp add: no_fail_def bind_def2 image_Un image_image
apply (simp add: no_fail_def bind_def' image_Un image_image
in_image_constant)
apply (intro allI conjI impI)
apply (fastforce simp: image_def)

View File

@ -17,7 +17,8 @@ text \<open>
The dual to validity: an existential instead of a universal quantifier for the post condition.
In refinement, it is often sufficient to know that there is one state that satisfies a condition.\<close>
definition exs_valid ::
"('a \<Rightarrow> bool) \<Rightarrow> ('a, 'b) tmonad \<Rightarrow> ('b \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> bool" ("\<lbrace>_\<rbrace> _ \<exists>\<lbrace>_\<rbrace>") where
"('a \<Rightarrow> bool) \<Rightarrow> ('a, 'b) tmonad \<Rightarrow> ('b \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> bool"
("\<lbrace>_\<rbrace> _ \<exists>\<lbrace>_\<rbrace>") where
"\<lbrace>P\<rbrace> f \<exists>\<lbrace>Q\<rbrace> \<equiv> \<forall>s. P s \<longrightarrow> (\<exists>(rv, s') \<in> mres (f s). Q rv s')"
text \<open>The above for the exception monad\<close>
@ -86,7 +87,7 @@ lemma exs_valid_assume_pre:
lemma exs_valid_bind[wp_split]:
"\<lbrakk> \<And>rv. \<lbrace>B rv\<rbrace> g rv \<exists>\<lbrace>C\<rbrace>; \<lbrace>A\<rbrace> f \<exists>\<lbrace>B\<rbrace> \<rbrakk> \<Longrightarrow> \<lbrace>A\<rbrace> f >>= (\<lambda>rv. g rv) \<exists>\<lbrace>C\<rbrace>"
apply atomize
apply (clarsimp simp: exs_valid_def bind_def2 mres_def)
apply (clarsimp simp: exs_valid_def bind_def' mres_def)
apply (drule spec, drule(1) mp, clarsimp)
apply (drule spec2, drule(1) mp, clarsimp)
apply (simp add: image_def bex_Un)

View File

@ -20,7 +20,8 @@ text \<open>
is often similar. The following definitions allow such reasoning to take place.\<close>
definition validNF ::
"('s \<Rightarrow> bool) \<Rightarrow> ('s,'a) tmonad \<Rightarrow> ('a \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> bool" ("\<lbrace>_\<rbrace>/ _ /\<lbrace>_\<rbrace>!") where
"('s \<Rightarrow> bool) \<Rightarrow> ('s,'a) tmonad \<Rightarrow> ('a \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> bool"
("\<lbrace>_\<rbrace>/ _ /\<lbrace>_\<rbrace>!") where
"\<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace>! \<equiv> \<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace> \<and> no_fail P f"
lemma validNF_alt_def:
@ -304,7 +305,8 @@ lemma validNF_nobindE[wp]:
text \<open>
Set up triple rules for @{term validE_NF} so that we can use @{method wp} combinator rules.\<close>
definition validE_NF_property ::
"('a \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> ('c \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> 's \<Rightarrow> ('s, 'c+'a) tmonad \<Rightarrow> bool" where
"('a \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> ('c \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> 's \<Rightarrow> ('s, 'c+'a) tmonad \<Rightarrow> bool"
where
"validE_NF_property Q E s b \<equiv>
Failed \<notin> snd ` (b s) \<and> (\<forall>(r', s') \<in> mres (b s). case r' of Inl x \<Rightarrow> E x s' | Inr x \<Rightarrow> Q x s')"

View File

@ -34,15 +34,15 @@ text \<open>
@{term "assert P"} does not require us to prove that @{term P} holds, but
rather allows us to assume @{term P}! Proving non-failure is done via a
separate predicate and calculus (see Trace_No_Fail).\<close>
definition valid :: "('s \<Rightarrow> bool) \<Rightarrow> ('s,'a) tmonad \<Rightarrow> ('a \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> bool"
definition valid ::
"('s \<Rightarrow> bool) \<Rightarrow> ('s,'a) tmonad \<Rightarrow> ('a \<Rightarrow> 's \<Rightarrow> bool) \<Rightarrow> bool"
("\<lbrace>_\<rbrace>/ _ /\<lbrace>_\<rbrace>") where
"\<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace> \<equiv> \<forall>s. P s \<longrightarrow> (\<forall>(r,s') \<in> mres (f s). Q r s')"
text \<open>
We often reason about invariant predicates. The following provides shorthand syntax
that avoids repeating potentially long predicates.\<close>
abbreviation (input) invariant ::
"('s,'a) tmonad \<Rightarrow> ('s \<Rightarrow> bool) \<Rightarrow> bool" ("_ \<lbrace>_\<rbrace>" [59,0] 60) where
abbreviation (input) invariant :: "('s,'a) tmonad \<Rightarrow> ('s \<Rightarrow> bool) \<Rightarrow> bool" ("_ \<lbrace>_\<rbrace>" [59,0] 60) where
"invariant f P \<equiv> \<lbrace>P\<rbrace> f \<lbrace>\<lambda>_. P\<rbrace>"
text \<open>
@ -143,7 +143,7 @@ subsection "Hoare Logic Rules"
lemma bind_wp[wp_split]:
"\<lbrakk> \<And>r. \<lbrace>Q' r\<rbrace> g r \<lbrace>Q\<rbrace>; \<lbrace>P\<rbrace>f \<lbrace>Q'\<rbrace> \<rbrakk> \<Longrightarrow> \<lbrace>P\<rbrace> f >>= (\<lambda>rv. g rv) \<lbrace>Q\<rbrace>"
by (fastforce simp: valid_def bind_def2 mres_def intro: image_eqI[rotated])
by (fastforce simp: valid_def bind_def' mres_def intro: image_eqI[rotated])
lemma seq':
"\<lbrakk> \<lbrace>A\<rbrace> f \<lbrace>B\<rbrace>; \<forall>x. P x \<longrightarrow> \<lbrace>C\<rbrace> g x \<lbrace>D\<rbrace>; \<forall>x s. B x s \<longrightarrow> P x \<and> C s \<rbrakk> \<Longrightarrow>
@ -467,7 +467,7 @@ lemma in_image_constant:
lemma hoare_liftM_subst:
"\<lbrace>P\<rbrace> liftM f m \<lbrace>Q\<rbrace> = \<lbrace>P\<rbrace> m \<lbrace>Q \<circ> f\<rbrace>"
apply (simp add: liftM_def bind_def2 return_def split_def)
apply (simp add: liftM_def bind_def' return_def split_def)
apply (simp add: valid_def Ball_def mres_def image_Un)
apply (simp add: image_image in_image_constant)
apply force
@ -554,6 +554,15 @@ lemma hoare_vcg_conj_liftE1:
unfolding valid_def validE_R_def validE_def
by (fastforce simp: split_def split: sum.splits)
lemma hoare_vcg_conj_liftE_weaker:
assumes "\<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace>, \<lbrace>E\<rbrace>"
assumes "\<lbrace>P'\<rbrace> f \<lbrace>Q'\<rbrace>, \<lbrace>E\<rbrace>"
shows "\<lbrace>\<lambda>s. P s \<and> P' s\<rbrace> f \<lbrace>\<lambda>rv s. Q rv s \<and> Q' rv s\<rbrace>, \<lbrace>E\<rbrace>"
apply (rule hoare_pre)
apply (fastforce intro: assms hoare_vcg_conj_liftE1 validE_validE_R hoare_post_impErr)
apply simp
done
lemma hoare_vcg_disj_lift:
"\<lbrakk> \<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace>; \<lbrace>P'\<rbrace> f \<lbrace>Q'\<rbrace> \<rbrakk> \<Longrightarrow> \<lbrace>\<lambda>s. P s \<or> P' s\<rbrace> f \<lbrace>\<lambda>rv s. Q rv s \<or> Q' rv s\<rbrace>"
unfolding valid_def
@ -585,6 +594,19 @@ lemma hoare_vcg_imp_lift':
"\<lbrakk> \<lbrace>P'\<rbrace> f \<lbrace>\<lambda>rv s. \<not> P rv s\<rbrace>; \<lbrace>Q'\<rbrace> f \<lbrace>Q\<rbrace> \<rbrakk> \<Longrightarrow> \<lbrace>\<lambda>s. \<not> P' s \<longrightarrow> Q' s\<rbrace> f \<lbrace>\<lambda>rv s. P rv s \<longrightarrow> Q rv s\<rbrace>"
by (wpsimp wp: hoare_vcg_imp_lift)
lemma hoare_vcg_imp_liftE:
"\<lbrakk> \<lbrace>P'\<rbrace> f \<lbrace>\<lambda>rv s. \<not> P rv s\<rbrace>, \<lbrace>A\<rbrace>; \<lbrace>Q'\<rbrace> f \<lbrace>Q\<rbrace>, \<lbrace>A\<rbrace> \<rbrakk>
\<Longrightarrow> \<lbrace>\<lambda>s. \<not> P' s \<longrightarrow> Q' s\<rbrace> f \<lbrace>\<lambda>rv s. P rv s \<longrightarrow> Q rv s\<rbrace>, \<lbrace>A\<rbrace>"
by (fastforce simp: validE_def valid_def split: sum.splits)
lemma hoare_vcg_imp_lift_R:
"\<lbrakk> \<lbrace>P'\<rbrace> f \<lbrace>\<lambda>rv s. \<not> P rv s\<rbrace>, -; \<lbrace>Q'\<rbrace> f \<lbrace>Q\<rbrace>, - \<rbrakk> \<Longrightarrow> \<lbrace>\<lambda>s. P' s \<or> Q' s\<rbrace> f \<lbrace>\<lambda>rv s. P rv s \<longrightarrow> Q rv s\<rbrace>, -"
by (auto simp add: valid_def validE_R_def validE_def split_def split: sum.splits)
lemma hoare_vcg_imp_lift_R':
"\<lbrakk> \<lbrace>P'\<rbrace> f \<lbrace>\<lambda>rv s. \<not> P rv s\<rbrace>, -; \<lbrace>Q'\<rbrace> f \<lbrace>Q\<rbrace>, - \<rbrakk> \<Longrightarrow> \<lbrace>\<lambda>s. \<not>P' s \<longrightarrow> Q' s\<rbrace> f \<lbrace>\<lambda>rv s. P rv s \<longrightarrow> Q rv s\<rbrace>, -"
by (auto simp add: valid_def validE_R_def validE_def split_def split: sum.splits)
lemma hoare_vcg_imp_conj_lift[wp_comb]:
"\<lbrakk> \<lbrace>P\<rbrace> f \<lbrace>\<lambda>rv s. Q rv s \<longrightarrow> Q' rv s\<rbrace>; \<lbrace>P'\<rbrace> f \<lbrace>\<lambda>rv s. (Q rv s \<longrightarrow> Q'' rv s) \<and> Q''' rv s\<rbrace> \<rbrakk> \<Longrightarrow>
\<lbrace>P and P'\<rbrace> f \<lbrace>\<lambda>rv s. (Q rv s \<longrightarrow> Q' rv s \<and> Q'' rv s) \<and> Q''' rv s\<rbrace>"
@ -605,6 +627,10 @@ lemma hoare_vcg_const_imp_lift:
"\<lbrakk> P \<Longrightarrow> \<lbrace>Q\<rbrace> m \<lbrace>R\<rbrace> \<rbrakk> \<Longrightarrow> \<lbrace>\<lambda>s. P \<longrightarrow> Q s\<rbrace> m \<lbrace>\<lambda>rv s. P \<longrightarrow> R rv s\<rbrace>"
by (cases P, simp_all add: hoare_vcg_prop)
lemma hoare_vcg_const_imp_lift_E:
"(P \<Longrightarrow> \<lbrace>Q\<rbrace> f -, \<lbrace>R\<rbrace>) \<Longrightarrow> \<lbrace>\<lambda>s. P \<longrightarrow> Q s\<rbrace> f -, \<lbrace>\<lambda>rv s. P \<longrightarrow> R rv s\<rbrace>"
by (fastforce simp: validE_E_def validE_def valid_def split_def split: sum.splits)
lemma hoare_vcg_const_imp_lift_R:
"(P \<Longrightarrow> \<lbrace>Q\<rbrace> m \<lbrace>R\<rbrace>,-) \<Longrightarrow> \<lbrace>\<lambda>s. P \<longrightarrow> Q s\<rbrace> m \<lbrace>\<lambda>rv s. P \<longrightarrow> R rv s\<rbrace>,-"
by (fastforce simp: validE_R_def validE_def valid_def split_def split: sum.splits)
@ -708,6 +734,58 @@ lemma hoare_post_comb_imp_conj:
"\<lbrakk> \<lbrace>P'\<rbrace> f \<lbrace>Q\<rbrace>; \<lbrace>P\<rbrace> f \<lbrace>Q'\<rbrace>; \<And>s. P s \<Longrightarrow> P' s \<rbrakk> \<Longrightarrow> \<lbrace>P\<rbrace> f \<lbrace>\<lambda>rv s. Q rv s \<and> Q' rv s\<rbrace>"
by (wpsimp wp: hoare_vcg_conj_lift)
lemma hoare_vcg_if_lift:
"\<lbrace>R\<rbrace> f \<lbrace>\<lambda>rv s. (P \<longrightarrow> X rv s) \<and> (\<not>P \<longrightarrow> Y rv s)\<rbrace> \<Longrightarrow>
\<lbrace>R\<rbrace> f \<lbrace>\<lambda>rv s. if P then X rv s else Y rv s\<rbrace>"
"\<lbrace>R\<rbrace> f \<lbrace>\<lambda>rv s. (P \<longrightarrow> X rv s) \<and> (\<not>P \<longrightarrow> Y rv s)\<rbrace> \<Longrightarrow>
\<lbrace>R\<rbrace> f \<lbrace>\<lambda>rv. if P then X rv else Y rv\<rbrace>"
by (auto simp: valid_def split_def)
lemma hoare_vcg_disj_lift_R:
assumes x: "\<lbrace>P\<rbrace> f \<lbrace>Q\<rbrace>,-"
assumes y: "\<lbrace>P'\<rbrace> f \<lbrace>Q'\<rbrace>,-"
shows "\<lbrace>\<lambda>s. P s \<or> P' s\<rbrace> f \<lbrace>\<lambda>rv s. Q rv s \<or> Q' rv s\<rbrace>,-"
using assms
by (fastforce simp: validE_R_def validE_def valid_def split: sum.splits)
lemma hoare_vcg_all_liftE:
"\<lbrakk> \<And>x. \<lbrace>P x\<rbrace> f \<lbrace>Q x\<rbrace>,\<lbrace>E\<rbrace> \<rbrakk> \<Longrightarrow> \<lbrace>\<lambda>s. \<forall>x. P x s\<rbrace> f \<lbrace>\<lambda>rv s. \<forall>x. Q x rv s\<rbrace>,\<lbrace>E\<rbrace>"
by (fastforce simp: validE_def valid_def split: sum.splits)
lemma hoare_vcg_const_Ball_liftE:
"\<lbrakk> \<And>x. x \<in> S \<Longrightarrow> \<lbrace>P x\<rbrace> f \<lbrace>Q x\<rbrace>,\<lbrace>E\<rbrace>; \<lbrace>\<lambda>s. True\<rbrace> f \<lbrace>\<lambda>r s. True\<rbrace>, \<lbrace>E\<rbrace> \<rbrakk> \<Longrightarrow> \<lbrace>\<lambda>s. \<forall>x\<in>S. P x s\<rbrace> f \<lbrace>\<lambda>rv s. \<forall>x\<in>S. Q x rv s\<rbrace>,\<lbrace>E\<rbrace>"
by (fastforce simp: validE_def valid_def split: sum.splits)
lemma hoare_vcg_split_lift[wp]:
"\<lbrace>P\<rbrace> f x y \<lbrace>Q\<rbrace> \<Longrightarrow> \<lbrace>P\<rbrace> case (x, y) of (a, b) \<Rightarrow> f a b \<lbrace>Q\<rbrace>"
by simp
named_theorems hoare_vcg_op_lift
lemmas [hoare_vcg_op_lift] =
hoare_vcg_const_imp_lift
hoare_vcg_const_imp_lift_E
hoare_vcg_const_imp_lift_R
(* leaving out hoare_vcg_conj_lift*, because that is built into wp *)
hoare_vcg_disj_lift
hoare_vcg_disj_lift_R
hoare_vcg_ex_lift
hoare_vcg_ex_liftE
hoare_vcg_ex_liftE_E
hoare_vcg_all_lift
hoare_vcg_all_liftE
hoare_vcg_all_liftE_E
hoare_vcg_all_lift_R
hoare_vcg_const_Ball_lift
hoare_vcg_const_Ball_lift_R
hoare_vcg_const_Ball_lift_E_E
hoare_vcg_split_lift
hoare_vcg_if_lift
hoare_vcg_imp_lift'
hoare_vcg_imp_liftE
hoare_vcg_imp_lift_R
hoare_vcg_imp_liftE_E
subsection \<open>Weakest Precondition Rules\<close>

View File

@ -23,7 +23,7 @@ lemma triv_refinement_mono_bind:
"(\<forall>x. triv_refinement (b x) (d x)) \<Longrightarrow> triv_refinement (a >>= b) (a >>= d)"
apply (simp add: triv_refinement_def bind_def)
apply (intro allI UN_mono; simp)
apply (simp only: triv_refinement_def bind_def2 split_def)
apply (simp only: triv_refinement_def bind_def' split_def)
apply (intro Un_mono allI order_refl UN_mono image_mono)
apply simp
done