File ‹CTR_Relators.ML›
signature CTR_RELATORS =
sig
structure RelatorData: GENERIC_DATA
val get_relator_data_generic : Context.generic -> RelatorData.T
val get_relator_data_proof : Proof.context -> RelatorData.T
val get_relator_data_global : theory -> RelatorData.T
val relator_of_generic : Context.generic -> Symtab.key -> term option
val relator_of_proof : Proof.context -> Symtab.key -> term option
val relator_of_global : theory -> Symtab.key -> term option
val update_relator : Symtab.key -> term -> local_theory -> local_theory
val process_ctr_relator : string -> Proof.context -> local_theory
val pr_of_typ : Proof.context -> ((string * sort) * term) list -> typ -> term
val bnf_relator_of_type_name : Proof.context -> string -> term option
end;
structure CTR_Relators : CTR_RELATORS =
struct
structure RelatorData = Generic_Data
(
type T = term Symtab.table
val empty = Symtab.empty
val merge = Symtab.merge (K true)
);
val get_relator_data_generic = RelatorData.get;
val get_relator_data_proof = Context.Proof #> get_relator_data_generic;
val get_relator_data_global = Context.Theory #> get_relator_data_generic;
fun relator_of_generic context = context
|> get_relator_data_generic
|> Symtab.lookup
#>
(
context
|> Context.theory_of
|> (Morphism.transfer_morphism #> Morphism.term)
|> Option.map
);
val relator_of_proof = Context.Proof #> relator_of_generic;
val relator_of_global = Context.Theory #> relator_of_generic;
fun update_relator k rel = Local_Theory.declaration
{pervasive=true, syntax=false, pos = ⌂}
(fn phi => (k, Morphism.term phi rel) |> Symtab.update |> RelatorData.map);
fun mk_msg_ctr_relator msg = "ctr_relator: " ^ msg;
val mk_msg_not_const = "the input must be a constant term";
val mk_msg_not_body_bool = "the body of the type of the input must be bool";
val mk_msg_not_binders_2 =
"the type of the input must have more than two binders";
val mk_msg_not_binders_binrelT =
"all of the binders associated with the type of the input" ^
"except the last two must be the binary relation types";
val mk_msg_no_dup_binrelT =
"the types of the binders of the binary relations associated " ^
"with the type of the input must have no duplicates";
val mk_msg_not_binders_binrelT_ftv_stv =
"the types of the binders of the binary relation types associated " ^
"with the input type must be either free type variables or " ^
"schematic type variables";
val mk_msg_not_type_constructor =
"the last two binders of the input type must be " ^
"the results of an application of a type constructor";
val mk_msg_not_identical_type_constructors =
"the type constructors that are associated with the last two binders " ^
"of the input type must be identical";
val mk_msg_not_identical_input_types =
"the sequences of the input types to the type constructors that are " ^
"associated with the last two binders of the input type must be " ^
"identical to the sequences of the types formed by concatenating the " ^
"type variables associated with the left hand side and the right " ^
"hand side of the binary relation types, respectively";
fun relator_type_name_of_type T =
let
val _ = T |> body_type |> curry op= HOLogic.boolT
orelse error (mk_msg_ctr_relator mk_msg_not_body_bool)
val binders = binder_types T
val n = length binders
val _ = n |> (fn n => n > 2)
orelse error (mk_msg_ctr_relator mk_msg_not_binders_2)
val (relTs, (mainT_lhs, mainT_rhs)) = binders
|> chop (n - 2)
||> chop 1
||> apfst the_single
||> apsnd the_single
val _ = relTs |> map HOLogic.is_binrelT |> List.all I
orelse error (mk_msg_ctr_relator mk_msg_not_binders_binrelT)
val (lhs_tvars, rhs_tvars) = relTs
|> map HOLogic.dest_binrelT
|> split_list
val tvars = lhs_tvars @ rhs_tvars
val _ = tvars |> has_duplicates op= |> not
orelse error (mk_msg_ctr_relator mk_msg_no_dup_binrelT)
val _ = tvars |> map (fn T => is_TVar T orelse is_TFree T) |> List.all I
orelse error (mk_msg_ctr_relator mk_msg_not_binders_binrelT_ftv_stv)
val _ = is_Type mainT_lhs
orelse error (mk_msg_ctr_relator mk_msg_not_type_constructor)
val _ = is_Type mainT_rhs
orelse error (mk_msg_ctr_relator mk_msg_not_type_constructor)
val mainT_lhs = dest_Type mainT_lhs
val mainT_rhs = dest_Type mainT_rhs
val _ = op= (apply2 #1 (mainT_lhs, mainT_rhs))
orelse error (mk_msg_ctr_relator mk_msg_not_identical_type_constructors)
val _ = lhs_tvars = #2 mainT_lhs
orelse error (mk_msg_ctr_relator mk_msg_not_identical_input_types)
val _ = rhs_tvars = #2 mainT_rhs
orelse error (mk_msg_ctr_relator mk_msg_not_identical_input_types)
in #1 mainT_lhs end;
fun process_ctr_relator args ctxt =
let
val t = Syntax.read_term ctxt args
val _ = is_Const t orelse error (mk_msg_ctr_relator mk_msg_not_const)
val c = relator_type_name_of_type (type_of t)
in update_relator c t ctxt end;
val _ = Outer_Syntax.local_theory
\<^command_keyword>‹ctr_relator›
"registration of the ctr relators"
(Parse.const >> process_ctr_relator);
fun bnf_relator_of_type_name ctxt c =
let
fun bnf_relator_of_type_name ctxt c =
let
val relator_of_bnf = BNF_Def.rel_of_bnf
#> strip_comb
#> #1
#> dest_Const
#> #1
#> Syntax.read_term ctxt
#> Logic.varify_global
in c |> BNF_Def.bnf_of ctxt |> Option.map relator_of_bnf end
in
case relator_of_proof ctxt c of
SOME t => SOME t
| NONE => bnf_relator_of_type_name ctxt c
end;
fun pr_of_typ ctxt ftv_spec_relt T =
let
fun pr_of_typ _ trel (TFree ftv_spec) = trel ftv_spec
| pr_of_typ _ _ (Type (c, [])) =
Const
(
\<^const_name>‹HOL.eq›,
HOLogic.mk_binrelT (Type (c, []), Type (c, []))
)
| pr_of_typ relator_of_type_name trel (Type (c, Ts)) =
let
val constt = relator_of_type_name c
handle Option =>
raise TYPE ("pr_of_typ: no relator", [Type (c, Ts)], [])
val constT = type_of constt
val binders = constT |> binder_types |> take (length Ts)
val argts = map (pr_of_typ relator_of_type_name trel) Ts
val argTs = map type_of argts
val tyenv_match = Type.typ_matches
(Proof_Context.tsig_of ctxt) (binders, argTs) Vartab.empty
handle Type.TYPE_MATCH =>
raise TYPE ("pr_of_typ: invalid relator", [Type (c, Ts)], [])
val constt = constt
|> dest_Const
||> K (Envir.subst_type tyenv_match constT)
|> Const
in list_comb (constt, argts) end
| pr_of_typ _ _ T = raise TYPE ("pr_of_typ: type", single T, [])
val trel = AList.lookup op= ftv_spec_relt #> the
in pr_of_typ (bnf_relator_of_type_name ctxt #> the) trel T end;
end;