lh-l4v/lib/Monads/Fun_Pred_Syntax.thy

211 lines
7.1 KiB
Plaintext

(*
* Copyright 2022, Proofcraft Pty Ltd
*
* SPDX-License-Identifier: BSD-2-Clause
*)
(* Syntax for using multi-argument functions as predicates, e.g "P and Q" where P and Q are
functions to bool, taking one or more parameters. *)
theory Fun_Pred_Syntax
imports Main
begin
section \<open>Definitions\<close>
text \<open>
Functions are already instances of Boolean algebras and provide all the standard laws one
would like to have. Default simplifications are automatic. Search for @{const inf}/
@{const sup}/@{const uminus} to find further laws and/or unfold via the definitions below.
The abbreviations here provide special syntax for the function instance of Boolean
algebras only, leaving other instances (such as @{typ bool}) untouched.\<close>
abbreviation pred_conj :: "('a \<Rightarrow> 'b::boolean_algebra) \<Rightarrow> ('a \<Rightarrow> 'b) \<Rightarrow> ('a \<Rightarrow> 'b)" where
"pred_conj \<equiv> inf"
abbreviation pred_disj :: "('a \<Rightarrow> 'b::boolean_algebra) \<Rightarrow> ('a \<Rightarrow> 'b) \<Rightarrow> ('a \<Rightarrow> 'b)" where
"pred_disj \<equiv> sup"
abbreviation pred_neg :: "('a \<Rightarrow> 'b::boolean_algebra) \<Rightarrow> ('a \<Rightarrow> 'b)" where
"pred_neg \<equiv> uminus"
text \<open>
Lifted True/False: ideally, we'd map these to top/bot, but top/bot are constants and there are
currently too many rules and tools that expect these conditions to beta-reduce and match against
True/False directly.\<close>
abbreviation (input) pred_top :: "'a \<Rightarrow> bool" where
"pred_top \<equiv> \<lambda>_. True"
abbreviation (input) pred_bot :: "'a \<Rightarrow> bool" where
"pred_bot \<equiv> \<lambda>_. False"
text \<open>Version with two arguments for compatibility. Can hopefully be eliminated at some point.\<close>
abbreviation (input) pred_top2 :: "'a \<Rightarrow> 'b \<Rightarrow> bool" where
"pred_top2 \<equiv> \<lambda>_ _. True"
abbreviation (input) pred_bot2 :: "'a \<Rightarrow> 'b \<Rightarrow> bool" where
"pred_bot2 \<equiv> \<lambda>_ _. False"
section \<open>Syntax bundles\<close>
bundle fun_pred_syntax
begin
(* infixl instead of infixr, because we want to split off conjuncts from the left *)
notation pred_conj (infixl "and" 35)
notation pred_disj (infixl "or" 30)
notation pred_neg ("not _" [40] 40)
notation pred_top ("\<top>")
notation pred_bot ("\<bottom>")
notation pred_top2 ("\<top>\<top>")
notation pred_bot2 ("\<bottom>\<bottom>")
end
bundle no_fun_pred_syntax
begin
no_notation pred_conj (infixl "and" 35)
no_notation pred_disj (infixl "or" 30)
no_notation pred_neg ("not _" [40] 40)
no_notation pred_top ("\<top>")
no_notation pred_bot ("\<bottom>")
no_notation pred_top2 ("\<top>\<top>")
no_notation pred_bot2 ("\<bottom>\<bottom>")
end
unbundle fun_pred_syntax
section \<open>Definitions specialised to @{typ bool} and @{text fun} instance of @{class boolean_algebra}\<close>
lemmas pred_conj_def =
inf_fun_def[where 'b=bool, simplified]
inf_fun_def[where f="f::'a \<Rightarrow> 'b::boolean_algebra" for f]
lemmas pred_disj_def =
sup_fun_def[where 'b=bool, simplified]
sup_fun_def[where f="f::'a \<Rightarrow> 'b::boolean_algebra" for f]
lemmas pred_neg_def =
fun_Compl_def[where 'b=bool, simplified]
fun_Compl_def[where A="A::'a \<Rightarrow> 'b::boolean_algebra" for A]
lemmas pred_top_def[simp] =
top_fun_def[where 'b=bool, simplified] top_fun_def[where 'b="'b::boolean_algebra"]
lemmas pred_bot_def[simp] =
bot_fun_def[where 'b=bool, simplified] bot_fun_def[where 'b="'b::boolean_algebra"]
section \<open>Other lemmas\<close>
text \<open>AC rewriting renamed and specialised, so we don't have to remember inf/sup\<close>
lemmas pred_conj_aci = inf_aci[where 'a="'a \<Rightarrow> 'b::boolean_algebra"]
lemmas pred_disj_aci = sup_aci[where 'a="'a \<Rightarrow> 'b::boolean_algebra"]
text \<open>Useful legacy names\<close>
lemmas pred_conjI = inf1I inf2I
lemmas pred_disjI1 = sup1I1[where 'a="'a \<Rightarrow> 'b::boolean_algebra"]
lemmas pred_disjI2 = sup1I2[where 'a="'a \<Rightarrow> 'b::boolean_algebra"]
lemmas pred_disj1CI[intro!] = sup1CI[where 'a="'a \<Rightarrow> 'b::boolean_algebra"]
lemmas pred_disj2CI = sup2CI[where 'a="'a \<Rightarrow> 'b::boolean_algebra"]
lemmas pred_conj_assoc = inf.assoc[where 'a="'a \<Rightarrow> 'b::boolean_algebra", symmetric]
lemmas pred_conj_comm = inf.commute[where 'a="'a \<Rightarrow> 'b::boolean_algebra"]
lemmas pred_disj_assoc = sup.assoc[where 'a="'a \<Rightarrow> 'b::boolean_algebra", symmetric]
lemmas pred_disj_comm = sup.commute[where 'a="'a \<Rightarrow> 'b::boolean_algebra"]
text \<open>Top/bot and function composition\<close>
lemma pred_top_comp[simp]:
"\<top> \<circ> f = \<top>"
by (simp add: comp_def)
lemma pred_bot_comp[simp]:
"\<bottom> \<circ> f = \<bottom>"
by (simp add: comp_def)
text \<open>We would get these for free if we could instantiate pred_top/pred_bot to top/bot directly:\<close>
lemmas pred_top_left_neutral[simp] =
inf_top.left_neutral[where 'a="'a \<Rightarrow> bool", unfolded pred_top_def]
lemmas pred_top_right_neutral[simp] =
inf_top.right_neutral[where 'a="'a \<Rightarrow> bool", unfolded pred_top_def]
lemmas pred_bot_left_neutral[simp] =
sup_bot.left_neutral[where 'a="'a \<Rightarrow> bool", unfolded pred_bot_def]
lemmas pred_bot_right_neutral[simp] =
sup_bot.right_neutral[where 'a="'a \<Rightarrow> bool", unfolded pred_bot_def]
lemmas pred_top_left[simp] =
sup_top_left[where 'a="'a \<Rightarrow> bool", unfolded pred_top_def]
lemmas pred_top_right[simp] =
sup_top_right[where 'a="'a \<Rightarrow> bool", unfolded pred_top_def]
lemmas pred_bot_left[simp] =
inf_bot_left[where 'a="'a \<Rightarrow> bool", unfolded pred_bot_def]
lemmas pred_bot_right[simp] =
inf_bot_right[where 'a="'a \<Rightarrow> bool", unfolded pred_bot_def]
lemmas pred_neg_top_eq[simp] =
compl_top_eq[where 'a="'a \<Rightarrow> bool", unfolded pred_bot_def pred_top_def]
lemmas pred_neg_bot_eq[simp] =
compl_bot_eq[where 'a="'a \<Rightarrow> bool", unfolded pred_bot_def pred_top_def]
(* no special setup for pred_top2/pred_bot2 at the moment, since we hope to eliminate these
entirely in the future *)
section \<open>Examples\<close>
experiment
begin
(* Standard laws are available by default: *)
lemma "(P and P) = P" for P :: "'a \<Rightarrow> bool"
by simp
(* Works for functions with multiple arguments: *)
lemma "(P and Q) = (Q and P)" for P :: "'a \<Rightarrow> 'b \<Rightarrow> bool"
by (simp add: pred_conj_aci)
(* Unfolds automatically when applied: *)
lemma "(P and Q) s t = (P s t \<and> Q s t)"
by simp
(* pred_top and pred_bot work for only one argument currently: *)
lemma "(P and not P) = \<bottom>" for P :: "'a \<Rightarrow> bool"
by simp
(* You can still use them with more arguments and sometimes get simplification: *)
lemma "(P and not P) = (\<lambda>_ _. \<bottom>)" for P :: "'a \<Rightarrow> 'b \<Rightarrow> 'c \<Rightarrow> bool"
by simp
(* But sometimes you need to fold pred_top_def/pred_bot_def for rules on top/bot to fire: *)
lemma "(P and (\<lambda>_ _. \<bottom>)) = (\<lambda>_ _. \<bottom>)"
by (simp flip: pred_bot_def)
lemma "(P and \<bottom>\<bottom>) = \<bottom>\<bottom>"
by (simp flip: pred_bot_def)
end
end