Theory With_Type
section ‹‹With_Type› -- Setting up the \<^term>‹with_type› mechanism›
theory With_Type
imports "HOL-Types_To_Sets.Types_To_Sets" Misc_With_Type "HOL-Eisbach.Eisbach"
keywords "with_type_case" :: prf_asm % "proof"
begin
definition with_type_wellformed where
‹with_type_wellformed C S R ⟷ (∀r rp. bi_unique r ⟶ right_total r ⟶ S = Collect (Domainp r) ⟶ C S rp ⟶ Domainp (R r) rp)›
for C :: ‹'rep set ⇒ 'rep_ops ⇒ bool›
and S :: ‹'rep set›
and R :: ‹('rep ⇒ 'abs ⇒ bool) ⇒ ('rep_ops ⇒ 'abs_ops ⇒ bool)›
text ‹
In the following definition, roughly speaking, \<^term>‹with_type C R S rep_ops P› means that predicate \<^term>‹P› holds whenever
type \<^typ>‹'abs› (called the abstract type, and determined by the type of \<^term>‹P›)
is an instance of the type class described by C,R, and is a stands in 1-1 correspondence
to the subset \<^term>‹S› of some concrete type \<^typ>‹'rep› (i.e., as if defined by
‹typedef 'abs = S›).
\<^term>‹S› -- the carrier set of the representation of the type (concrete type)
\<^term>‹rep_ops› -- operations on the concrete type (i.e., operations like addition or similar)
\<^term>‹C› -- the properties that \<^term>‹S› and \<^term>‹rep_ops› are guaranteed to satisfy
(basically, the type-class definition)
\<^term>‹R› -- transfers a relation \<^term>‹r› between concrete/abstract type to a relation
between concrete/abstract operations (\<^term>‹r› is always bi-unique and right-total)
\<^term>‹P› -- the predicate that we claim holds.
It can work on the type \<^typ>‹'abs› (which is type-classed) but it also gets \<^term>‹rep› and \<^term>‹abs_ops›
where \<^term>‹rep› is an embedding of the abstract into the concrete type, and \<^term>‹abs_ops› operations on the abstract type.
The intuitive meaning of \<^term>‹with_type C R S rep_ops P› is that \<^term>‹P› holds for
any type \<^typ>‹'t› that that can be represented by a concrete representation \<^term>‹(S,rep_ops)›
and that has a type class matching the specification \<^term>‹(C,R)›.
›
definition ‹with_type = (λC R S rep_ops P. S≠{} ∧ C S rep_ops ∧ with_type_wellformed C S R
∧ (∀rep abs_ops. bij_betw rep UNIV S ⟶ (R (λx y. x = rep y) rep_ops abs_ops) ⟶
P rep abs_ops))›
for S :: ‹'rep set› and P :: ‹('abs ⇒ 'rep) ⇒ 'abs_ops ⇒ bool›
and R :: ‹('rep ⇒ 'abs ⇒ bool) ⇒ ('rep_ops ⇒ 'abs_ops ⇒ bool)›
and C :: ‹'rep set ⇒ 'rep_ops ⇒ bool›
and rep_ops :: ‹'rep_ops›
text ‹For every type class that we want to use with \<^const>‹with_type›, we need to define two
constants specifying the axioms of the class (\<^term>‹WITH_TYPE_CLASS_classname›) and
specifying how a relation between concrete/abstract type is lifted to a relation between
concrete/abstract operations (\<^term>‹WITH_TYPE_REL_classname›). Here we give the
trivial definitions for the default type class \<^class>‹type››
definition ‹WITH_TYPE_CLASS_type S ops = True› for S :: ‹'rep set› and ops :: unit
definition ‹WITH_TYPE_REL_type r = ((=) :: unit ⇒ _ ⇒ _)› for r :: ‹'rep ⇒ 'abs ⇒ bool›
named_theorems with_type_intros
lemma [with_type_intros]: ‹WITH_TYPE_CLASS_type S ops›
by (simp add: WITH_TYPE_CLASS_type_def)
text ‹We need to show that \<^term>‹WITH_TYPE_CLASS_classname› and \<^term>‹WITH_TYPE_REL_classname›
are wellbehaved. We do this here for class \<^class>‹type›. We will need this lemma also for
registering the type class \<^class>‹type› later.›
lemma with_type_wellformed_type[with_type_intros]:
‹with_type_wellformed WITH_TYPE_CLASS_type S WITH_TYPE_REL_type›
by (simp add: WITH_TYPE_REL_type_def WITH_TYPE_CLASS_type_def with_type_wellformed_def Domainp_iff)
lemma with_type_simple: ‹with_type WITH_TYPE_CLASS_type WITH_TYPE_REL_type S () P ⟷ S≠{} ∧ (∀rep. bij_betw rep UNIV S ⟶ P rep ())›
by (auto simp: with_type_def WITH_TYPE_REL_type_def WITH_TYPE_CLASS_type_def with_type_wellformed_def)
lemma with_typeI:
assumes ‹S ≠ {}›
assumes ‹C S p›
assumes ‹with_type_wellformed C S R›
assumes main: ‹⋀(rep :: 'abs ⇒ 'rep) abs_ops. bij_betw rep UNIV S ⟹ R (λx y. x = rep y) p abs_ops ⟹ P rep abs_ops›
shows ‹with_type C R S p P›
using assms
by (auto intro!: simp: with_type_def)
lemma with_type_mp:
assumes ‹with_type C R S p P›
assumes ‹⋀rep abs_ops. bij_betw rep UNIV S ⟹ C S p ⟹ P rep abs_ops ⟹ Q rep abs_ops›
shows ‹with_type C R S p Q›
using assms by (auto simp add: with_type_def case_prod_beta type_definition_bij_betw_iff)
lemma with_type_nonempty: ‹with_type C R S p P ⟹ S ≠ {}›
by (simp add: with_type_def case_prod_beta)
lemma with_type_prepare_cancel:
fixes S :: ‹'rep set› and P :: bool
and R :: ‹('rep ⇒ 'abs ⇒ bool) ⇒ ('rep_ops ⇒ 'abs_ops ⇒ bool)›
and C :: ‹'rep set ⇒ 'rep_ops ⇒ bool›
and p :: ‹'rep_ops›
assumes wt: ‹with_type C R S p (λ(_::'abs⇒'rep) _. P)›
assumes ex: ‹(∃(rep::'abs⇒'rep) abs. type_definition rep abs S)›
shows P
proof -
from ex
obtain rep :: ‹'abs ⇒ 'rep› and abs where td: ‹type_definition rep abs S›
by auto
then have bij: ‹bij_betw rep UNIV S›
by (simp add: bij_betw_def inj_on_def type_definition.Rep_inject type_definition.Rep_range)
define r where ‹r = (λx y. x = rep y)›
have [simp]: ‹bi_unique r› ‹right_total r›
using r_def td typedef_bi_unique apply blast
by (simp add: r_def right_totalI)
have aux1: ‹(⋀x. rep x ∈ S) ⟹ x ∈ S ⟹ x = rep (abs x)› for x b
using td type_definition.Abs_inverse by fastforce
have Sr: ‹S = Collect (Domainp r)›
using type_definition.Rep[OF td]
by (auto simp: r_def intro!: DomainPI aux1)
from wt have nice: ‹with_type_wellformed C S R› and ‹C S p›
by (simp_all add: with_type_def case_prod_beta)
from nice[unfolded with_type_wellformed_def, rule_format, OF ‹bi_unique r› ‹right_total r› Sr ‹C S p›]
obtain abs_ops where abs_ops: ‹R (λx y. x = rep y) p abs_ops›
apply atomize_elim by (auto simp: r_def)
from bij abs_ops wt
show P
by (auto simp: with_type_def case_prod_beta)
qed
lemma with_type_transfer_class:
includes lifting_syntax
fixes Rep :: ‹'abs ⇒ 'rep›
and C S
and R :: ‹('rep⇒'abs⇒bool) ⇒ ('rep_ops ⇒ 'abs_ops ⇒ bool)›
and R2 :: ‹('rep⇒'abs2⇒bool) ⇒ ('rep_ops ⇒ 'abs_ops2 ⇒ bool)›
assumes trans: ‹⋀r :: 'rep ⇒ 'abs2 ⇒ bool. bi_unique r ⟹ right_total r ⟹ (R2 r ===> (⟷)) (C (Collect (Domainp r))) axioms›
assumes nice: ‹with_type_wellformed C S R2›
assumes wt: ‹with_type C R S p P›
assumes ex: ‹∃(Rep :: 'abs2⇒'rep) Abs. type_definition Rep Abs S›
shows ‹∃x::'abs_ops2. axioms x›
proof -
from ex obtain Rep :: ‹'abs2⇒'rep› and Abs where td: ‹type_definition Rep Abs S›
by auto
define r where ‹r x y = (x = Rep y)› for x y
have bi_unique_r: ‹bi_unique r›
using bi_unique_def td type_definition.Rep_inject r_def by fastforce
have right_total_r: ‹right_total r›
by (simp add: right_totalI r_def)
have right_total_R[transfer_rule]: ‹right_total (r ===> r ===> r)›
by (meson bi_unique_r right_total_r bi_unique_alt_def right_total_fun)
note trans = trans[OF bi_unique_r, OF right_total_r, transfer_rule]
from td
have rS: ‹Collect (Domainp r) = S›
by (auto simp: r_def Domainp_iff type_definition.Rep elim!: type_definition.Rep_cases[where P=‹Ex _›])
from wt have sg: ‹C S p›
by (simp_all add: with_type_def case_prod_beta)
with nice have ‹Domainp (R2 r) p›
by (simp add: bi_unique_r with_type_wellformed_def rS right_total_r)
with sg
have ‹∃x :: 'abs_ops2. axioms x›
apply (transfer' fixing: R2 S p)
using apply_rsp' local.trans rS by fastforce
then obtain abs_plus :: 'abs_ops2
where abs_plus: ‹axioms abs_plus›
apply atomize_elim by auto
then show ?thesis
by auto
qed
lemma with_type_transfer_class2:
includes lifting_syntax
fixes Rep :: ‹'abs ⇒ 'rep›
and C S
and R :: ‹('rep⇒'abs⇒bool) ⇒ ('rep_ops ⇒ 'abs itself ⇒ bool)›
and R2 :: ‹('rep⇒'abs2⇒bool) ⇒ ('rep_ops ⇒ 'abs2 itself ⇒ bool)›
assumes trans: ‹⋀r :: 'rep ⇒ 'abs2 ⇒ bool. bi_unique r ⟹ right_total r ⟹ (R2 r ===> (⟷)) (C (Collect (Domainp r))) axioms›
assumes nice: ‹with_type_wellformed C S R2›
assumes rel_itself: ‹⋀(r :: 'rep ⇒ 'abs2 ⇒ bool) p. bi_unique r ⟹ right_total r ⟹ (R2 r) p TYPE('abs2)›
assumes wt: ‹with_type C R S p P›
assumes ex: ‹∃(Rep :: 'abs2⇒'rep) Abs. type_definition Rep Abs S›
shows ‹axioms TYPE('abs2)›
proof -
from ex obtain Rep :: ‹'abs2⇒'rep› and Abs where td: ‹type_definition Rep Abs S›
by auto
define r where ‹r x y = (x = Rep y)› for x y
have bi_unique_r: ‹bi_unique r›
using bi_unique_def td type_definition.Rep_inject r_def by fastforce
have right_total_r: ‹right_total r›
by (simp add: right_totalI r_def)
have right_total_R[transfer_rule]: ‹right_total (r ===> r ===> r)›
by (meson bi_unique_r right_total_r bi_unique_alt_def right_total_fun)
from td
have rS: ‹Collect (Domainp r) = S›
by (auto simp: r_def Domainp_iff type_definition.Rep elim!: type_definition.Rep_cases[where P=‹Ex _›])
note trans = trans[OF bi_unique_r, OF right_total_r, unfolded rS, transfer_rule]
note rel_itself = rel_itself[OF bi_unique_r, OF right_total_r, of p, transfer_rule]
from wt have sg: ‹C S p›
by (simp_all add: with_type_def case_prod_beta)
then show ‹axioms TYPE('abs2)›
by transfer
qed
text ‹Syntactic constants for rendering \<^const>‹with_type› nicely.›
syntax "_with_type" :: "type ⇒ 'a => 'b ⇒ 'c" ("let _ = _ in _" [0,0,10] 10)
syntax "_with_type_with" :: "type ⇒ 'a => args ⇒ 'b ⇒ 'c" ("let _ = _ with _ in _" [0,0,10] 10)
syntax (output) "_with_type_sort_annotation" :: "type ⇒ sort ⇒ type" ("_::_")
ML_file "with_type.ML"
text ‹Register the type class \<^class>‹type› with the \<^const>‹with_type›-mechanism.
This enables readable syntax, and contains information needed by various tools
such as the ‹cancel_with_type› attribute.›
setup ‹
With_Type.add_with_type_info_global {
class = \<^class>‹type›,
rep_class = \<^const_name>‹WITH_TYPE_CLASS_type›,
rep_rel = \<^const_name>‹WITH_TYPE_REL_type›,
with_type_wellformed = @{thm with_type_wellformed_type},
param_names = [],
transfer = NONE,
rep_rel_itself = NONE
}›
text ‹Enabling input/output syntax for \<^const>‹with_type›. This allows to write, e.g.,
‹let 't::type = S in P›, and the various relevant parameters such as \<^const>‹WITH_TYPE_CLASS_type› etc.
are automatically looked up based on the indicated type class.
This only works with type classes that have been registered beforehand.
Using the syntax when printing can be disabled by ‹declare [[with_type_syntax=false]]›.›
parse_translation ‹[
(\<^syntax_const>‹_with_type›, With_Type.with_type_parse_translation),
(\<^syntax_const>‹_with_type_with›, With_Type.with_type_parse_translation)
]›
typed_print_translation ‹[ (\<^const_syntax>‹with_type›, With_Type.with_type_print_translation) ]›
text ‹Example of input syntax:›
term ‹let 't::type = N in rep_t = rep_t›
text ‹Removes a toplevel ‹let 't=…› from a proposition ‹let 't=… in P›.
This only works if \<^term>‹P› does not refer to the type \<^typ>‹'t›.›
attribute_setup cancel_with_type =
‹Thm.rule_attribute [] (With_Type.cancel_with_type o Context.proof_of) |> Scan.succeed›
‹Transforms (let 't=… in P) into P›
text ‹Convenience method for proving a theorem of the form ‹let 't=…›.›
method with_type_intro = rule with_typeI; (intro with_type_intros)?
text ‹Method for doing a modus ponens inside ‹let 't=…›.
Use as: ‹using PREMISE proof with_type_mp›.
And inside the proof, use the command ‹with_type_case› before proving the main goal.
Try ‹print_theorems› after ‹with_type_case› to see what it sets up.
›
method_setup with_type_mp = ‹Scan.succeed () >>
(fn (_) => fn ctxt => CONTEXT_METHOD (fn facts =>
Method.RUNTIME (With_Type.with_type_mp_tac ⌂ facts)))›
ML ‹
val _ =
Outer_Syntax.command \<^command_keyword>‹with_type_case› "Sets up local proof after the \<^method>‹with_type_mp› method (for the main goal)."
(Scan.repeat (Parse.maybe Parse.binding) >> (fn args => Toplevel.proof (With_Type.with_type_case_cmd args)))
›
end