Theory Typerep

(* Author: Florian Haftmann, TU Muenchen *)

section ‹Reflecting Pure types into HOL›

theory Typerep
imports String
begin

datatype typerep = Typerep String.literal "typerep list"

class typerep =
  fixes typerep :: "'a itself ⇒ typerep"
begin

definition typerep_of :: "'a ⇒ typerep" where
  [simp]: "typerep_of x = typerep TYPE('a)"

end

syntax
  "_TYPEREP" :: "type => logic"  (‹(‹indent=1 notation=‹mixfix TYPEREP››TYPEREP/(1'(_')))›)
syntax_consts
  "_TYPEREP" ⇌ typerep

parse_translation ‹
  let
    fun typerep_tr (*"_TYPEREP"*) [ty] =
          Syntax.const const_syntax‹typerep› $
            (Syntax.const syntax_const‹_constrain› $ Syntax.const const_syntax‹Pure.type› $
              (Syntax.const type_syntax‹itself› $ ty))
      | typerep_tr (*"_TYPEREP"*) ts = raise TERM ("typerep_tr", ts);
  in [(syntax_const‹_TYPEREP›, K typerep_tr)] end
›

typed_print_translation ‹
  let
    fun typerep_tr' ctxt (*"typerep"*) Type‹fun Type‹itself T› _›
            (Const (const_syntax‹Pure.type›, _) :: ts) =
          Term.list_comb
            (Syntax.const syntax_const‹_TYPEREP› $ Syntax_Phases.term_of_typ ctxt T, ts)
      | typerep_tr' _ T ts = raise Match;
  in [(const_syntax‹typerep›, typerep_tr')] end
›

setup ‹
let

fun add_typerep tyco thy =
  let
    val sorts = replicate (Sign.arity_number thy tyco) sort‹typerep›;
    val vs = Name.invent_types_global sorts;
    val ty = Type (tyco, map TFree vs);
    val lhs = Const‹typerep ty› $ Free ("T", Term.itselfT ty);
    val rhs = Const‹Typerep› $ HOLogic.mk_literal tyco
      $ HOLogic.mk_list Type‹typerep› (map (HOLogic.mk_typerep o TFree) vs);
    val eq = HOLogic.mk_Trueprop (HOLogic.mk_eq (lhs, rhs));
  in
    thy
    |> Class.instantiation ([tyco], vs, sort‹typerep›)
    |> `(fn lthy => Syntax.check_term lthy eq)
    |-> (fn eq => Specification.definition NONE [] [] (Binding.empty_atts, eq))
    |> snd
    |> Class.prove_instantiation_exit (fn ctxt => Class.intro_classes_tac ctxt [])
  end;

fun ensure_typerep tyco thy =
  if not (Sorts.has_instance (Sign.classes_of thy) tyco sort‹typerep›)
    andalso Sorts.has_instance (Sign.classes_of thy) tyco sort‹type›
  then add_typerep tyco thy else thy;

in

add_typerep type_name‹fun›
#> Typedef.interpretation (Local_Theory.background_theory o ensure_typerep)
#> Code.type_interpretation ensure_typerep

end
›

lemma [code]:
  "HOL.equal (Typerep tyco1 tys1) (Typerep tyco2 tys2) ⟷ HOL.equal tyco1 tyco2
     ∧ list_all2 HOL.equal tys1 tys2"
  by (auto simp add: eq_equal [symmetric] list_all2_eq [symmetric])

lemma [code nbe]:
  "HOL.equal (x :: typerep) x ⟷ True"
  by (fact equal_refl)

code_printing
  type_constructor typerep ⇀ (Eval) "Term.typ"
| constant Typerep ⇀ (Eval) "Term.Type/ (_, _)"

code_reserved
  (Eval) Term

hide_const (open) typerep Typerep

end