[isabelle-dev] adhoc overloading

Christian Sternagel c.sternagel at gmail.com
Wed Jul 10 09:38:05 CEST 2013


First of all, thanks for all the useful answers and sorry for my late 
reply (I visited a conference and had some holidays ;)). As Alexander 
suggested, I first tried to modify the existing adhoc_overloading.ML in 
such a way that variants may be arbitrary terms. Please find the results 
of my attempt attached (the new adhoc_overloading.ML as well as a 
patch-file). Now I will investigate further localization.

Any comments are welcome.

cheers

chris

On 06/02/2013 08:55 AM, Alexander Krauss wrote:
> Hi Chris,
>
>> I'm currently (as of changeset e6433b34364b) investigating whether it
>> would be possible to allow adhoc overloading (implemented in
>> ~~/src/Tools/adhoc_overloading.ML) inside local contexts.
>
> Nice!
>
>> For completeness find my current adhoc_overloading.ML attached
>
> Apart from the various formalities pointed out by Makarius, here is
> another concern, which relates to Florian's earlier question about how
> local you want to be...
>
> Currently, Adhoc_Overloading replaces constants with other constants,
> which makes it global-only. Your current version tries to deal with
> Frees similarly, it's not just that. Recall the example you gave
> previously:
>
>    consts FOO :: ... (<some syntax>)
>    setup {* Adhoc_Overloading.add_overloaded @{const_name FOO} *}
>
>    locale foo =
>      fixes foo :: ...
>      assumes ...
>    begin
>
>    local_setup {*
>      Adhoc_Overloading.add_variant @{const_name FOO} @{term foo}
>    *}
>
> Now consider the following interpretation:
>
>    interpretation foo "<some term>"
>      <proof>
>
> Now, <some term> should become a variant of FOO, so at least the variant
> side of the overloading relation must be an arbitrary term. With your
> current code, the overloading would only survive interpretations where
> foo happens to be mapped to a constant.
>
> So, I guess that the overloaded constants should remain constants, since
> they are just syntactic anyway. It seems that localizing those would be
> rather artificial. But the variants must be properly localized and
> subject to the morphism.
>
> As a step towards proper localization, you could start with the global
> code, and first generalize it to accept arbitrary terms as variants.
> Note that this touches in particular the uncheck phase, which can no
> longer use Term_Subst.map_aterms_same (or Term.map_aterms), since it
> becomes general rewriting. One must resort to the more general
> Pattern.rewrite_term here. When all this is working again, the actual
> localization is then a mere formality, of which you have already
> discovered the ingredients.
>
> Makarius wrote:
>> * Same.function seems to be a let-over from the version by Alex
>> Krauss. He had that once in his function package, copied from
>> somewhere else (probably old code of mine).
>
> No, it has nothing to do with the function package, which never used any
> "Same" stuff. It just arose rather naturally from the requirement to
> return NONE when nothing changes... So it was not meant as an optimization.
>
>> There is no point to do
>> such low-level optimizations in the syntax layer.  It is for hardcore
>> kernel operations only
>
> So should I manually check the result for equality, or does the
> framework do this for me?
>
> Alex

-------------- next part --------------
(* Author: Alexander Krauss, TU Muenchen
   Author: Christian Sternagel, University of Innsbruck

Ad-hoc overloading of constants based on their types.
*)

signature ADHOC_OVERLOADING =
sig
  val add_overloaded: string -> theory -> theory
  val add_variant: string -> term -> theory -> theory

  val show_variants: bool Config.T
  val setup: theory -> theory
end

structure Adhoc_Overloading: ADHOC_OVERLOADING =
struct

val show_variants = Attrib.setup_config_bool @{binding show_variants} (K false);


(* errors *)

fun duplicate_variant_error ext_name =
  error ("Duplicate variant of " ^ quote ext_name);

fun not_overloaded_error name =
  error ("Constant " ^ quote name ^ " is not declared as overloaded");

fun already_overloaded_error name =
  error ("Constant " ^ quote name ^ " is already declared as overloaded");

fun unresolved_overloading_error ctxt (c, T) t reason =
  error ("Unresolved overloading of  " ^ quote c ^ " :: " ^
    quote (Syntax.string_of_typ ctxt T) ^ " in " ^
    quote (Syntax.string_of_term ctxt t) ^ " (" ^ reason ^ ")");


(* theory data *)

structure Overload_Data = Theory_Data
(
  type T =
    {internalize : term list Symtab.table,
     externalize : string Termtab.table};
  val empty = {internalize = Symtab.empty, externalize = Termtab.empty};
  val extend = I;

  fun merge_ext _ (ext_name1, ext_name2) =
    if ext_name1 = ext_name2 then ext_name1
    else duplicate_variant_error ext_name1;

  fun merge
    ({internalize = int1, externalize = ext1},
     {internalize = int2, externalize = ext2}) : T =
    {internalize = Symtab.merge_list (op aconv) (int1, int2),
     externalize = Termtab.join merge_ext (ext1, ext2)};
);

fun map_tables f g =
  Overload_Data.map (fn {internalize = int, externalize = ext} =>
    {internalize = f int, externalize = g ext});

val is_overloaded = Symtab.defined o #internalize o Overload_Data.get;
val get_variants = Symtab.lookup o #internalize o Overload_Data.get;
val get_external = Termtab.lookup o #externalize o Overload_Data.get;

fun add_overloaded ext_name thy =
  let val _ = not (is_overloaded thy ext_name) orelse already_overloaded_error ext_name;
  in map_tables (Symtab.update (ext_name, [])) I thy end;

fun add_variant ext_name variant thy =
  let
    val _ = is_overloaded thy ext_name orelse not_overloaded_error ext_name;
    val _ =
      (case get_external thy variant of
        NONE => ()
      | SOME gen' => duplicate_variant_error gen');
  in
    map_tables (Symtab.cons_list (ext_name, variant))
      (Termtab.update (variant, ext_name)) thy
  end


(* check / uncheck *)

fun unifiable_with ctxt T1 variant =
  let
    val T2 = fastype_of variant;
    val thy = Proof_Context.theory_of ctxt;
    val maxidx1 = Term.maxidx_of_typ T1;
    val T2' = Logic.incr_tvar (maxidx1 + 1) T2;
    val maxidx2 = Int.max (maxidx1, Term.maxidx_of_typ T2');
  in
    (Sign.typ_unify thy (T1, T2') (Vartab.empty, maxidx2); SOME variant)
    handle Type.TUNIFY => NONE
  end;

fun insert_internal_same ctxt t (Const (c, T)) =
      (case map_filter (unifiable_with ctxt T)
         (Same.function (get_variants (Proof_Context.theory_of ctxt)) c) of
        [] => unresolved_overloading_error ctxt (c, T) t "no instances"
      | [variant] => variant
      | _ => raise Same.SAME)
  | insert_internal_same _ _ _ = raise Same.SAME;

fun insert_external_same ctxt variant =
  let
    val thy = Proof_Context.theory_of ctxt;
    val t' = Pattern.rewrite_term thy [] [fn t =>
      get_external thy t
      |> Option.map (fn c => Const (c, fastype_of variant))] variant;
  in if variant aconv t' then raise Same.SAME else t' end;

fun gen_check_uncheck replace ts ctxt =
  Same.capture (Same.map replace) ts
  |> Option.map (rpair ctxt);

fun check ts ctxt =
  gen_check_uncheck (fn t =>
    Term_Subst.map_aterms_same (insert_internal_same ctxt t) t) ts ctxt;

fun uncheck ts ctxt =
  if Config.get ctxt show_variants then NONE
  else gen_check_uncheck (insert_external_same ctxt) ts ctxt;

fun reject_unresolved ts ctxt =
  let
    val thy = Proof_Context.theory_of ctxt;
    fun check_unresolved t =
      (case filter (is_overloaded thy o fst) (Term.add_consts t []) of
        [] => ()
      | ((c, T) :: _) => unresolved_overloading_error ctxt (c, T) t "multiple instances");
    val _ = map check_unresolved ts;
  in NONE end;


(* setup *)

val setup = Context.theory_map
  (Syntax_Phases.term_check' 0 "adhoc_overloading" check
   #> Syntax_Phases.term_check' 1 "adhoc_overloading_unresolved_check" reject_unresolved
   #> Syntax_Phases.term_uncheck' 0 "adhoc_overloading" uncheck);

end;

-------------- next part --------------
A non-text attachment was scrubbed...
Name: adhoc_overloading.ML.patch
Type: text/x-patch
Size: 4588 bytes
Desc: not available
URL: <https://mailmanbroy.informatik.tu-muenchen.de/pipermail/isabelle-dev/attachments/20130710/676e3105/attachment-0001.bin>


More information about the isabelle-dev mailing list