aboutsummaryrefslogtreecommitdiff
path: root/HoTT_Typing.thy
diff options
context:
space:
mode:
Diffstat (limited to 'HoTT_Typing.thy')
-rw-r--r--HoTT_Typing.thy169
1 files changed, 169 insertions, 0 deletions
diff --git a/HoTT_Typing.thy b/HoTT_Typing.thy
new file mode 100644
index 0000000..6433139
--- /dev/null
+++ b/HoTT_Typing.thy
@@ -0,0 +1,169 @@
+(********
+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 \<open>Initial settings\<close>
+
+declare[[eta_contract=false]] \<comment> \<open>Do not eta-contract\<close>
+
+ML \<open>val trace = Attrib.setup_config_bool @{binding "trace"} (K false)\<close>
+ \<comment> \<open>Context attribute for tracing; use declare[[trace=true]] at any point in a theory to turn on.\<close>
+
+
+section \<open>Terms and typing\<close>
+
+typedecl t \<comment> \<open>Type of object-logic terms (which includes the types)\<close>
+
+judgment has_type :: "[t, t] \<Rightarrow> prop" ("(3_:/ _)")
+
+
+section \<open>Typing functionality\<close>
+
+ML_file "util.ML"
+
+ML \<open>
+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
+\<close>
+
+ML \<open>
+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
+\<close>
+
+end