(******** Isabelle/HoTT: Core typing judgment form and associated automation Feb 2019 This file is the starting point of the definition of Isabelle/HoTT. It declares the fundamental typing judgment form and sets up various ML functionality to automate type inference. ********) theory HoTT_Typing imports Pure keywords "assume_type" "assume_types" :: thy_decl begin section \Initial settings\ declare[[eta_contract=false]] \ \Do not eta-contract\ ML \val trace = Attrib.setup_config_bool @{binding "trace"} (K false)\ \ \Context attribute for tracing; use declare[[trace=true]] at any point in a theory to turn on.\ section \Terms and typing\ typedecl t \ \Type of object-logic terms (which includes the types)\ judgment has_type :: "[t, t] \ prop" ("(3_ :/ _)") section \Typing functionality\ ML_file "util.ML" ML \ signature TYPING = sig type jmt = term val is_typing_jmt: term -> bool val term_of_jmt: jmt -> term val type_of_jmt: jmt -> term val typing_this: Proof.context -> jmt list val typing_assms: Proof.context -> jmt list val typing_all: Proof.context -> jmt list val get_typing_in: term -> jmt list -> term option val get_local_typing: Proof.context -> term -> term option val put_theory_typing: term -> theory -> theory val get_theory_typing: theory -> term -> term option val get_typing: Proof.context -> term -> term option end structure Typing: TYPING = struct type jmt = term (* Determine if a term is a typing judgment *) fun is_typing_jmt (@{const has_type} $ _ $ _) = true | is_typing_jmt _ = false (* Functions to extract a and A from propositions "a: A" *) fun term_of_jmt (@{const has_type} $ t $ _) = t | term_of_jmt _ = Exn.error "Not a typing judgment" fun type_of_jmt (@{const has_type} $ _ $ T) = T | type_of_jmt _ = Exn.error "Not a typing judgment" (* Get typing assumptions in "this" *) fun typing_this ctxt = Util.get_this ctxt |> map Thm.prop_of |> filter is_typing_jmt (* Get the typing assumptions in the current proof context *) val typing_assms = Util.get_assms #> map Thm.prop_of #> filter is_typing_jmt (* Search the context and return all visible typing judgments *) fun typing_all ctxt = Util.get_all_thms ctxt |> map (Thm.prop_of o snd) |> filter is_typing_jmt (* Search for a term typing in a list of judgments, and return the type if found. -- The use of aconv_untyped as opposed to aconv is crucial here: meta-level type inference is performed *after* syntax translation, which means that the translation functions see an unannotated term "f" (in contrast to one annotated e.g. "f::t") as having a blank type field. Using aconv would result in no match ever being found for f, because any judgment involving f records it together with its (non-blank) type field, e.g. "Free ("f", "_")" seen by the translation function, vs. "Free ("f", "t")" recorded in the typing judgment. *) fun get_typing_in tm jmts = let val find_type = fn jmt => if Term.aconv_untyped (tm, term_of_jmt jmt) then SOME (type_of_jmt jmt) else NONE in get_first find_type jmts end (* Search for typing in the local proof context (no global data). We search the facts bound to "this" before searching the assumptions. -- A previous version of this function passed the argument (typing_this ctxt @ typing_assms ctxt) to get_typing_in. -- This version only evaluates successive lists if the search on the previous list was unsuccessful. *) fun get_local_typing ctxt tm = case get_typing_in tm (typing_this ctxt) of NONE => get_typing_in tm (typing_assms ctxt) | res => res (* Dedicated theory data for proven typing judgments *) structure Theory_Typings = Theory_Data ( type T = term Symtab.table val empty = Symtab.empty val extend = I val merge = Symtab.join (fn key => fn (x, y) => y) ) (* Accessor for the above data *) fun get_theory_typing thy tm = Symtab.lookup (Theory_Typings.get thy) (Util.string_of_term tm) fun put_theory_typing jmt = case jmt of Const("HoTT_Base.has_type", _) $ term $ typing => Theory_Typings.map (Symtab.update (Util.string_of_term term, typing)) | _ => Exn.error "Not a typing judgment" (* Get the typing of a term *) fun get_typing ctxt tm = case get_local_typing ctxt tm of NONE => get_theory_typing (Proof_Context.theory_of ctxt) tm | res => res end \ ML \ val _ = let fun store_typing ctxt = Typing.put_theory_typing o (Syntax.read_prop ctxt) in Outer_Syntax.local_theory @{command_keyword "assume_type"} "Declare typing assumptions" (Parse.prop >> (fn prop => fn lthy => Local_Theory.background_theory (store_typing lthy prop) lthy)) end val _ = let val parser = Parse.and_list (Parse.prop) fun store_typings ctxt = fold (Typing.put_theory_typing o (Syntax.read_prop ctxt)) in Outer_Syntax.local_theory @{command_keyword "assume_types"} "Declare typing assumptions" (parser >> (fn props => fn lthy => Local_Theory.background_theory (store_typings lthy props) lthy)) end \ end