products/Sources/formale Sprachen/Isabelle/HOL/Tools/BNF image not shown  

Quellcode-Bibliothek

© Kompilation durch diese Firma

[Weder Korrektheit noch Funktionsfähigkeit der Software werden zugesichert.]

Datei: RadarTestCase.java   Sprache: SML

Original von: Isabelle©

(*  Title:      HOL/Tools/BNF/bnf_fp_def_sugar.ML
    Author:     Jasmin Blanchette, TU Muenchen
    Author:     Martin Desharnais, TU Muenchen
    Copyright   2012, 2013, 2014

Sugared datatype and codatatype constructions.
*)


signature BNF_FP_DEF_SUGAR =
sig
  type fp_ctr_sugar =
    {ctrXs_Tss: typ list list,
     ctor_iff_dtor: thm,
     ctr_defs: thm list,
     ctr_sugar: Ctr_Sugar.ctr_sugar,
     ctr_transfers: thm list,
     case_transfers: thm list,
     disc_transfers: thm list,
     sel_transfers: thm list}

  type fp_bnf_sugar =
    {map_thms: thm list,
     map_disc_iffs: thm list,
     map_selss: thm list list,
     rel_injects: thm list,
     rel_distincts: thm list,
     rel_sels: thm list,
     rel_intros: thm list,
     rel_cases: thm list,
     pred_injects: thm list,
     set_thms: thm list,
     set_selssss: thm list list list list,
     set_introssss: thm list list list list,
     set_cases: thm list}

  type fp_co_induct_sugar =
    {co_rec: term,
     common_co_inducts: thm list,
     co_inducts: thm list,
     co_rec_def: thm,
     co_rec_thms: thm list,
     co_rec_discs: thm list,
     co_rec_disc_iffs: thm list,
     co_rec_selss: thm list list,
     co_rec_codes: thm list,
     co_rec_transfers: thm list,
     co_rec_o_maps: thm list,
     common_rel_co_inducts: thm list,
     rel_co_inducts: thm list,
     common_set_inducts: thm list,
     set_inducts: thm list}

  type fp_sugar =
    {T: typ,
     BT: typ,
     X: typ,
     fp: BNF_Util.fp_kind,
     fp_res_index: int,
     fp_res: BNF_FP_Util.fp_result,
     pre_bnf: BNF_Def.bnf,
     fp_bnf: BNF_Def.bnf,
     absT_info: BNF_Comp.absT_info,
     fp_nesting_bnfs: BNF_Def.bnf list,
     live_nesting_bnfs: BNF_Def.bnf list,
     fp_ctr_sugar: fp_ctr_sugar,
     fp_bnf_sugar: fp_bnf_sugar,
     fp_co_induct_sugar: fp_co_induct_sugar option}

  val co_induct_of: 'a list -> 'a
  val strong_co_induct_of: 'a list -> 'a

  val morph_fp_bnf_sugar: morphism -> fp_bnf_sugar -> fp_bnf_sugar
  val morph_fp_co_induct_sugar: morphism -> fp_co_induct_sugar -> fp_co_induct_sugar
  val morph_fp_ctr_sugar: morphism -> fp_ctr_sugar -> fp_ctr_sugar
  val morph_fp_sugar: morphism -> fp_sugar -> fp_sugar
  val transfer_fp_sugar: theory -> fp_sugar -> fp_sugar
  val fp_sugar_of: Proof.context -> string -> fp_sugar option
  val fp_sugar_of_global: theory -> string -> fp_sugar option
  val fp_sugars_of: Proof.context -> fp_sugar list
  val fp_sugars_of_global: theory -> fp_sugar list
  val fp_sugars_interpretation: string -> (fp_sugar list -> local_theory -> local_theory) ->
    theory -> theory
  val interpret_fp_sugars: (string -> bool) -> fp_sugar list -> local_theory -> local_theory
  val register_fp_sugars_raw: fp_sugar list -> local_theory -> local_theory
  val register_fp_sugars: (string -> bool) -> fp_sugar list -> local_theory -> local_theory

  val merge_type_args: BNF_Util.fp_kind -> ''list * ''list -> ''list
  val type_args_named_constrained_of_spec: (((('a * 'b) * 'c) * 'd) * 'e) * 'f -> 'a
  val type_binding_of_spec: (((('a * 'b) * 'c) * 'd) * 'e) * 'f -> 'b
  val mixfix_of_spec: ((('a * 'b) * 'c) * 'd) * 'e -> 'b
  val mixfixed_ctr_specs_of_spec: (('a * 'b) * 'c) * 'd -> 'b
  val map_binding_of_spec: ('a * ('b * 'c * 'd)) * 'e -> 'b
  val rel_binding_of_spec: ('a * ('b * 'c * 'd)) * 'e -> 'c
  val pred_binding_of_spec: ('a * ('b * 'c * 'd)) * 'e -> 'd
  val sel_default_eqs_of_spec: 'a * 'b -> 'b

  val mk_parametricity_goal: Proof.context -> term list -> term -> term -> term

  val flat_corec_preds_predsss_gettersss: 'a list -> 'list list list -> 'a list list list ->
    'a list
  val mk_ctor: typ list -> term -> term
  val mk_dtor: typ list -> term -> term
  val mk_bnf_sets: BNF_Def.bnf -> string * term list
  val liveness_of_fp_bnf: int -> BNF_Def.bnf -> bool list
  val nesting_bnfs: Proof.context -> typ list list list -> typ list -> BNF_Def.bnf list

  val massage_simple_notes: string -> (bstring * 'a list * (int -> 'b)) list ->
    ((binding * 'c list) * ('list * 'b) list) list
  val massage_multi_notes: string list -> typ list ->
    (string * 'a list list * (string -> 'b)) list ->
    ((binding * 'b) * ('list * 'c list) list) list

  val define_ctrs_dtrs_for_type: string -> typ -> term -> term -> thm -> thm -> int -> int list ->
    term -> binding list -> mixfix list -> typ list list -> local_theory ->
    (term list list * term list * thm * thm list) * local_theory
  val wrap_ctrs: (string -> bool) -> BNF_Util.fp_kind -> bool -> string -> thm -> int -> int list ->
    thm -> thm -> binding list -> binding list list -> term list -> term list -> thm -> thm list ->
    local_theory -> Ctr_Sugar.ctr_sugar * local_theory
  val derive_map_set_rel_pred_thms: (string -> bool) -> BNF_Util.fp_kind -> int -> typ list ->
    typ list -> typ -> typ -> thm list -> thm list -> thm list -> thm list -> thm list ->
    thm list -> thm list -> thm list -> thm list -> string -> BNF_Def.bnf -> BNF_Def.bnf list ->
    typ -> term -> thm -> thm -> thm -> thm list -> thm -> thm -> thm list -> thm -> thm list ->
    thm list -> thm list -> typ list list -> Ctr_Sugar.ctr_sugar -> local_theory ->
    (thm list * thm list * thm list list * thm list * thm list * thm list * thm list * thm list
     * thm list * thm list * thm list list list list * thm list list list list * thm list
     * thm list * thm list * thm list * thm list) * local_theory

  type lfp_sugar_thms = (thm list * thm * Token.src list) * (thm list list * Token.src list)

  val morph_lfp_sugar_thms: morphism -> lfp_sugar_thms -> lfp_sugar_thms
  val transfer_lfp_sugar_thms: theory -> lfp_sugar_thms -> lfp_sugar_thms

  type gfp_sugar_thms =
    ((thm list * thm) list * (Token.src list * Token.src list))
    * thm list list
    * thm list list
    * (thm list list * Token.src list)
    * (thm list list list * Token.src list)

  val morph_gfp_sugar_thms: morphism -> gfp_sugar_thms -> gfp_sugar_thms
  val transfer_gfp_sugar_thms: theory -> gfp_sugar_thms -> gfp_sugar_thms

  val mk_co_recs_prelims: Proof.context -> BNF_Util.fp_kind -> typ list list list -> typ list ->
     typ list -> typ list -> typ list -> int list -> int list list -> term list ->
     term list
     * (typ list list * typ list list list list * term list list * term list list list listoption
     * (string * term list * term list list
        * (((term list list * term list list * term list list list list * term list list list list)
            * term list list list) * typ list)) option
  val repair_nullary_single_ctr: typ list list -> typ list list
  val mk_corec_p_pred_types: typ list -> int list -> typ list list
  val mk_corec_fun_arg_types: typ list list list -> typ list -> typ list -> typ list -> int list ->
    int list list -> term ->
    typ list list
    * (typ list list list list * typ list list list * typ list list list list * typ list)
  val define_co_rec_as: BNF_Util.fp_kind -> typ list -> typ -> binding -> term -> local_theory ->
    (term * thm) * local_theory
  val define_rec:
    typ list list * typ list list list list * term list list * term list list list list ->
    (string -> binding) -> typ list -> typ list -> term list -> term -> Proof.context ->
    (term * thm) * Proof.context
  val define_corec: 'a * term list * term list list
      * (((term list list * term list list * term list list list list * term list list list list)
          * term list list list) * typ list) -> (string -> binding) -> 'b list -> typ list ->
    term list -> term -> local_theory -> (term * thm) * local_theory
  val mk_induct_raw_prem: (term -> term) -> Proof.context -> typ list list ->
    (string * term listlist -> term -> term -> typ list -> typ list ->
    term list * ((term * (term * term)) list * (int * term)) list * term
  val finish_induct_prem: Proof.context -> int -> term list ->
    term list * ((term * (term * term)) list * (int * term)) list * term -> term
  val mk_coinduct_prem: Proof.context -> typ list list -> typ list list -> term list -> term ->
    term -> term -> int -> term list -> term list list -> term list -> term list list ->
    typ list list -> term
  val mk_induct_attrs: term list list -> Token.src list
  val mk_coinduct_attrs: typ list -> term list list -> term list list -> int list list ->
    Token.src list * Token.src list
  val derive_induct_recs_thms_for_types: (string -> bool) -> BNF_Def.bnf list ->
     ('a * typ list list list list * term list list * 'b) option -> thm -> thm list ->
     BNF_Def.bnf list -> BNF_Def.bnf list -> typ list -> typ list -> typ list ->
     typ list list list -> thm list -> thm list -> thm list -> term list list -> thm list list ->
     term list -> thm list -> Proof.context -> lfp_sugar_thms
  val derive_coinduct_thms_for_types: Proof.context -> bool -> (term -> term) -> BNF_Def.bnf list ->
    thm -> thm list -> BNF_Def.bnf list -> typ list -> typ list -> typ list list list -> int list ->
    thm list -> thm list -> (thm -> thm) -> thm list list -> Ctr_Sugar.ctr_sugar list ->
    (thm list * thm) list
  val derive_coinduct_corecs_thms_for_types: Proof.context -> BNF_Def.bnf list ->
    string * term list * term list list
      * (((term list list * term list list * term list list list list * term list list list list)
          * term list list list) * typ list) ->
    thm -> thm list -> thm list -> thm list -> BNF_Def.bnf list -> typ list -> typ list ->
    typ list -> typ list list list -> int list list -> int list list -> int list -> thm list ->
    thm list -> (thm -> thm) -> thm list list -> Ctr_Sugar.ctr_sugar list -> term list ->
    thm list -> gfp_sugar_thms

  val co_datatypes: BNF_Util.fp_kind -> (mixfix list -> binding list -> binding list ->
      binding list -> binding list list -> binding list -> (string * sort) list ->
      typ list * typ list list -> BNF_Def.bnf list -> BNF_Comp.absT_info list -> local_theory ->
      BNF_FP_Util.fp_result * local_theory) ->
    Ctr_Sugar.ctr_options
    * ((((((binding option * (typ * sort)) list * binding) * mixfix)
         * ((binding, binding * typ) Ctr_Sugar.ctr_spec * mixfix) list) *
         (binding * binding * binding))
       * term listlist ->
    local_theory -> local_theory
  val co_datatype_cmd: BNF_Util.fp_kind ->
    (mixfix list -> binding list -> binding list -> binding list -> binding list list ->
      binding list -> (string * sort) list -> typ list * typ list list -> BNF_Def.bnf list ->
     BNF_Comp.absT_info list -> local_theory -> BNF_FP_Util.fp_result * Proof.context) ->
    ((Proof.context -> Plugin_Name.filter) * bool)
    * ((((((binding option * (string * string option)) list * binding) * mixfix)
         * ((binding, binding * string) Ctr_Sugar.ctr_spec * mixfix) list)
        * (binding * binding * binding)) * string listlist ->
    Proof.context -> local_theory

  val parse_ctr_arg: (binding * string) parser
  val parse_ctr_specs: ((binding, binding * string) Ctr_Sugar.ctr_spec * mixfix) list parser
  val parse_spec: ((((((binding option * (string * string option)) list * binding) * mixfix)
      * ((binding, binding * string) Ctr_Sugar.ctr_spec * mixfix) list)
    * (binding * binding * binding)) * string list) parser
  val parse_co_datatype: (Ctr_Sugar.ctr_options_cmd
        * ((((((binding option * (string * string option)) list * binding) * mixfix)
      * ((binding, binding * string) Ctr_Sugar.ctr_spec * mixfix) list)
    * (binding * binding * binding)) * string listlist) parser

  val parse_co_datatype_cmd: BNF_Util.fp_kind -> (mixfix list -> binding list -> binding list ->
      binding list -> binding list list -> binding list -> (string * sort) list ->
      typ list * typ list list -> BNF_Def.bnf list -> BNF_Comp.absT_info list -> local_theory ->
      BNF_FP_Util.fp_result * local_theory) ->
    (local_theory -> local_theory) parser
end;

structure BNF_FP_Def_Sugar : BNF_FP_DEF_SUGAR =
struct

open Ctr_Sugar
open BNF_FP_Rec_Sugar_Util
open BNF_Util
open BNF_Comp
open BNF_Def
open BNF_FP_Util
open BNF_FP_Def_Sugar_Tactics

val Eq_prefix = "Eq_";

val case_transferN = "case_transfer";
val ctor_iff_dtorN = "ctor_iff_dtor";
val ctr_transferN = "ctr_transfer";
val disc_transferN = "disc_transfer";
val sel_transferN = "sel_transfer";
val corec_codeN = "corec_code";
val corec_transferN = "corec_transfer";
val map_disc_iffN = "map_disc_iff";
val map_o_corecN = "map_o_corec";
val map_selN = "map_sel";
val pred_injectN = "pred_inject";
val rec_o_mapN = "rec_o_map";
val rec_transferN = "rec_transfer";
val set0N = "set0";
val set_casesN = "set_cases";
val set_introsN = "set_intros";
val set_inductN = "set_induct";
val set_selN = "set_sel";

type fp_ctr_sugar =
  {ctrXs_Tss: typ list list,
   ctor_iff_dtor: thm,
   ctr_defs: thm list,
   ctr_sugar: Ctr_Sugar.ctr_sugar,
   ctr_transfers: thm list,
   case_transfers: thm list,
   disc_transfers: thm list,
   sel_transfers: thm list};

type fp_bnf_sugar =
  {map_thms: thm list,
   map_disc_iffs: thm list,
   map_selss: thm list list,
   rel_injects: thm list,
   rel_distincts: thm list,
   rel_sels: thm list,
   rel_intros: thm list,
   rel_cases: thm list,
   pred_injects: thm list,
   set_thms: thm list,
   set_selssss: thm list list list list,
   set_introssss: thm list list list list,
   set_cases: thm list};

type fp_co_induct_sugar =
  {co_rec: term,
   common_co_inducts: thm list,
   co_inducts: thm list,
   co_rec_def: thm,
   co_rec_thms: thm list,
   co_rec_discs: thm list,
   co_rec_disc_iffs: thm list,
   co_rec_selss: thm list list,
   co_rec_codes: thm list,
   co_rec_transfers: thm list,
   co_rec_o_maps: thm list,
   common_rel_co_inducts: thm list,
   rel_co_inducts: thm list,
   common_set_inducts: thm list,
   set_inducts: thm list};

type fp_sugar =
  {T: typ,
   BT: typ,
   X: typ,
   fp: fp_kind,
   fp_res_index: int,
   fp_res: fp_result,
   pre_bnf: bnf,
   fp_bnf: bnf,
   absT_info: absT_info,
   fp_nesting_bnfs: bnf list,
   live_nesting_bnfs: bnf list,
   fp_ctr_sugar: fp_ctr_sugar,
   fp_bnf_sugar: fp_bnf_sugar,
   fp_co_induct_sugar: fp_co_induct_sugar option};

fun co_induct_of (i :: _) = i;
fun strong_co_induct_of [_, s] = s;

fun morph_fp_bnf_sugar phi ({map_thms, map_disc_iffs, map_selss, rel_injects, rel_distincts,
    rel_sels, rel_intros, rel_cases, pred_injects, set_thms, set_selssss, set_introssss,
    set_cases} : fp_bnf_sugar) =
  {map_thms = map (Morphism.thm phi) map_thms,
   map_disc_iffs = map (Morphism.thm phi) map_disc_iffs,
   map_selss = map (map (Morphism.thm phi)) map_selss,
   rel_injects = map (Morphism.thm phi) rel_injects,
   rel_distincts = map (Morphism.thm phi) rel_distincts,
   rel_sels = map (Morphism.thm phi) rel_sels,
   rel_intros = map (Morphism.thm phi) rel_intros,
   rel_cases = map (Morphism.thm phi) rel_cases,
   pred_injects = map (Morphism.thm phi) pred_injects,
   set_thms = map (Morphism.thm phi) set_thms,
   set_selssss = map (map (map (map (Morphism.thm phi)))) set_selssss,
   set_introssss = map (map (map (map (Morphism.thm phi)))) set_introssss,
   set_cases = map (Morphism.thm phi) set_cases};

fun morph_fp_co_induct_sugar phi ({co_rec, common_co_inducts, co_inducts, co_rec_def, co_rec_thms,
    co_rec_discs, co_rec_disc_iffs, co_rec_selss, co_rec_codes, co_rec_transfers, co_rec_o_maps,
    common_rel_co_inducts, rel_co_inducts, common_set_inducts, set_inducts} : fp_co_induct_sugar) =
  {co_rec = Morphism.term phi co_rec,
   common_co_inducts = map (Morphism.thm phi) common_co_inducts,
   co_inducts = map (Morphism.thm phi) co_inducts,
   co_rec_def = Morphism.thm phi co_rec_def,
   co_rec_thms = map (Morphism.thm phi) co_rec_thms,
   co_rec_discs = map (Morphism.thm phi) co_rec_discs,
   co_rec_disc_iffs = map (Morphism.thm phi) co_rec_disc_iffs,
   co_rec_selss = map (map (Morphism.thm phi)) co_rec_selss,
   co_rec_codes = map (Morphism.thm phi) co_rec_codes,
   co_rec_transfers = map (Morphism.thm phi) co_rec_transfers,
   co_rec_o_maps = map (Morphism.thm phi) co_rec_o_maps,
   common_rel_co_inducts = map (Morphism.thm phi) common_rel_co_inducts,
   rel_co_inducts = map (Morphism.thm phi) rel_co_inducts,
   common_set_inducts = map (Morphism.thm phi) common_set_inducts,
   set_inducts = map (Morphism.thm phi) set_inducts};

fun morph_fp_ctr_sugar phi ({ctrXs_Tss, ctor_iff_dtor, ctr_defs, ctr_sugar, ctr_transfers,
    case_transfers, disc_transfers, sel_transfers} : fp_ctr_sugar) =
  {ctrXs_Tss = map (map (Morphism.typ phi)) ctrXs_Tss,
   ctor_iff_dtor = Morphism.thm phi ctor_iff_dtor,
   ctr_defs = map (Morphism.thm phi) ctr_defs,
   ctr_sugar = morph_ctr_sugar phi ctr_sugar,
   ctr_transfers = map (Morphism.thm phi) ctr_transfers,
   case_transfers = map (Morphism.thm phi) case_transfers,
   disc_transfers = map (Morphism.thm phi) disc_transfers,
   sel_transfers = map (Morphism.thm phi) sel_transfers};

fun morph_fp_sugar phi ({T, BT, X, fp, fp_res, fp_res_index, pre_bnf, fp_bnf, absT_info,
    fp_nesting_bnfs, live_nesting_bnfs, fp_ctr_sugar, fp_bnf_sugar,
    fp_co_induct_sugar} : fp_sugar) =
  {T = Morphism.typ phi T,
   BT = Morphism.typ phi BT,
   X = Morphism.typ phi X,
   fp = fp,
   fp_res = morph_fp_result phi fp_res,
   fp_res_index = fp_res_index,
   pre_bnf = morph_bnf phi pre_bnf,
   fp_bnf = morph_bnf phi fp_bnf,
   absT_info = morph_absT_info phi absT_info,
   fp_nesting_bnfs = map (morph_bnf phi) fp_nesting_bnfs,
   live_nesting_bnfs = map (morph_bnf phi) live_nesting_bnfs,
   fp_ctr_sugar = morph_fp_ctr_sugar phi fp_ctr_sugar,
   fp_bnf_sugar = morph_fp_bnf_sugar phi fp_bnf_sugar,
   fp_co_induct_sugar = Option.map (morph_fp_co_induct_sugar phi) fp_co_induct_sugar};

val transfer_fp_sugar = morph_fp_sugar o Morphism.transfer_morphism;

structure Data = Generic_Data
(
  type T = fp_sugar Symtab.table;
  val empty = Symtab.empty;
  val extend = I;
  fun merge data : T = Symtab.merge (K true) data;
);

fun fp_sugar_of_generic context =
  Option.map (transfer_fp_sugar (Context.theory_of context)) o Symtab.lookup (Data.get context);

fun fp_sugars_of_generic context =
  Symtab.fold (cons o transfer_fp_sugar (Context.theory_of context) o snd) (Data.get context) [];

val fp_sugar_of = fp_sugar_of_generic o Context.Proof;
val fp_sugar_of_global = fp_sugar_of_generic o Context.Theory;

val fp_sugars_of = fp_sugars_of_generic o Context.Proof;
val fp_sugars_of_global = fp_sugars_of_generic o Context.Theory;

structure FP_Sugar_Plugin = Plugin(type T = fp_sugar list);

fun fp_sugars_interpretation name f =
  FP_Sugar_Plugin.interpretation name (fn fp_sugars => fn lthy =>
    f (map (transfer_fp_sugar (Proof_Context.theory_of lthy)) fp_sugars) lthy);

val interpret_fp_sugars = FP_Sugar_Plugin.data;

val register_fp_sugars_raw =
  fold (fn fp_sugar as {T = Type (s, _), ...} =>
    Local_Theory.declaration {syntax = false, pervasive = true}
      (fn phi => Data.map (Symtab.update (s, morph_fp_sugar phi fp_sugar))));

fun register_fp_sugars plugins fp_sugars =
  register_fp_sugars_raw fp_sugars #> interpret_fp_sugars plugins fp_sugars;

fun interpret_bnfs_register_fp_sugars plugins Ts BTs Xs fp pre_bnfs absT_infos fp_nesting_bnfs
    live_nesting_bnfs fp_res ctrXs_Tsss ctor_iff_dtors ctr_defss ctr_sugars co_recs co_rec_defs
    map_thmss common_co_inducts co_inductss co_rec_thmss co_rec_discss co_rec_selsss rel_injectss
    rel_distinctss map_disc_iffss map_selsss rel_selss rel_intross rel_casess pred_injectss
    set_thmss set_selsssss set_introsssss set_casess ctr_transferss case_transferss disc_transferss
    sel_transferss co_rec_disc_iffss co_rec_codess co_rec_transferss common_rel_co_inducts
    rel_co_inductss common_set_inducts set_inductss co_rec_o_mapss noted =
  let
    val fp_sugars =
      map_index (fn (kk, T) =>
        {T = T, BT = nth BTs kk, X = nth Xs kk, fp = fp, fp_res = fp_res, fp_res_index = kk,
         pre_bnf = nth pre_bnfs kk, absT_info = nth absT_infos kk,
         fp_bnf = nth (#bnfs fp_res) kk,
         fp_nesting_bnfs = fp_nesting_bnfs, live_nesting_bnfs = live_nesting_bnfs,
         fp_ctr_sugar =
           {ctrXs_Tss = nth ctrXs_Tsss kk,
            ctor_iff_dtor = nth ctor_iff_dtors kk,
            ctr_defs = nth ctr_defss kk,
            ctr_sugar = nth ctr_sugars kk,
            ctr_transfers = nth ctr_transferss kk,
            case_transfers = nth case_transferss kk,
            disc_transfers = nth disc_transferss kk,
            sel_transfers = nth sel_transferss kk},
         fp_bnf_sugar =
           {map_thms = nth map_thmss kk,
            map_disc_iffs = nth map_disc_iffss kk,
            map_selss = nth map_selsss kk,
            rel_injects = nth rel_injectss kk,
            rel_distincts = nth rel_distinctss kk,
            rel_sels = nth rel_selss kk,
            rel_intros = nth rel_intross kk,
            rel_cases = nth rel_casess kk,
            pred_injects = nth pred_injectss kk,
            set_thms = nth set_thmss kk,
            set_selssss = nth set_selsssss kk,
            set_introssss = nth set_introsssss kk,
            set_cases = nth set_casess kk},
         fp_co_induct_sugar = SOME
           {co_rec = nth co_recs kk,
            common_co_inducts = common_co_inducts,
            co_inducts = nth co_inductss kk,
            co_rec_def = nth co_rec_defs kk,
            co_rec_thms = nth co_rec_thmss kk,
            co_rec_discs = nth co_rec_discss kk,
            co_rec_disc_iffs = nth co_rec_disc_iffss kk,
            co_rec_selss = nth co_rec_selsss kk,
            co_rec_codes = nth co_rec_codess kk,
            co_rec_transfers = nth co_rec_transferss kk,
            co_rec_o_maps = nth co_rec_o_mapss kk,
            common_rel_co_inducts = common_rel_co_inducts,
            rel_co_inducts = nth rel_co_inductss kk,
            common_set_inducts = common_set_inducts,
            set_inducts = nth set_inductss kk}}
        |> morph_fp_sugar (substitute_noted_thm noted)) Ts;
  in
    register_fp_sugars_raw fp_sugars
    #> fold (interpret_bnf plugins) (#bnfs fp_res)
    #> interpret_fp_sugars plugins fp_sugars
  end;

fun quasi_unambiguous_case_names names =
  let
    val ps = map (`Long_Name.base_name) names;
    val dups = Library.duplicates (op =) (map fst ps);
    fun underscore s =
      let val ss = Long_Name.explode s
      in space_implode "_" (drop (length ss - 2) ss) end;
  in
    map (fn (base, full) => if member (op =) dups base then underscore full else base) ps
    |> Name.variant_list []
  end;

fun zipper_map f =
  let
    fun zed _ [] = []
      | zed xs (y :: ys) = f (xs, y, ys) :: zed (xs @ [y]) ys;
  in zed [] end;

fun cannot_merge_types fp =
  error ("Mutually " ^ co_prefix fp ^ "recursive types must have the same type parameters");

fun merge_type_arg fp T T' = if T = T' then T else cannot_merge_types fp;

fun merge_type_args fp (As, As') =
  if length As = length As' then map2 (merge_type_arg fp) As As' else cannot_merge_types fp;

fun type_args_named_constrained_of_spec (((((ncAs, _), _), _), _), _) = ncAs;
fun type_binding_of_spec (((((_, b), _), _), _), _) = b;
fun mixfix_of_spec ((((_, mx), _), _), _) = mx;
fun mixfixed_ctr_specs_of_spec (((_, mx_ctr_specs), _), _) = mx_ctr_specs;
fun map_binding_of_spec ((_, (b, _, _)), _) = b;
fun rel_binding_of_spec ((_, (_, b, _)), _) = b;
fun pred_binding_of_spec ((_, (_, _, b)), _) = b;
fun sel_default_eqs_of_spec (_, ts) = ts;

fun ctr_sugar_kind_of_fp_kind Least_FP = Datatype
  | ctr_sugar_kind_of_fp_kind Greatest_FP = Codatatype;

fun uncurry_thm 0 thm = thm
  | uncurry_thm 1 thm = thm
  | uncurry_thm n thm = rotate_prems ~1 (uncurry_thm (n - 1) (rotate_prems 1 (conjI RS thm)));

fun choose_binary_fun fs AB =
  find_first (fastype_of #> binder_types #> (fn [A, B] => AB = (A, B))) fs;
fun build_binary_fun_app fs t u =
  Option.map (rapp u o rapp t) (choose_binary_fun fs (fastype_of t, fastype_of u));

fun build_the_rel ctxt Rs Ts A B =
  build_rel [] ctxt Ts [] (the o choose_binary_fun Rs) (A, B);
fun build_rel_app ctxt Rs Ts t u =
  build_the_rel ctxt Rs Ts (fastype_of t) (fastype_of u) $ t $ u;

fun build_set_app ctxt A t = Term.betapply (build_set ctxt A (fastype_of t), t);

fun mk_parametricity_goal ctxt Rs t u =
  let val prem = build_the_rel ctxt Rs [] (fastype_of t) (fastype_of u) in
    HOLogic.mk_Trueprop (prem $ t $ u)
  end;

val name_of_set = name_of_const "set function" domain_type;

val fundefcong_attrs = @{attributes [fundef_cong]};
val nitpicksimp_attrs = @{attributes [nitpick_simp]};
val simp_attrs = @{attributes [simp]};

val lists_bmoc = fold (fn xs => fn t => Term.list_comb (t, xs));

fun flat_corec_predss_getterss qss gss = maps (op @) (qss ~~ gss);

fun flat_corec_preds_predsss_gettersss [] [qss] [gss] = flat_corec_predss_getterss qss gss
  | flat_corec_preds_predsss_gettersss (p :: ps) (qss :: qsss) (gss :: gsss) =
    p :: flat_corec_predss_getterss qss gss @ flat_corec_preds_predsss_gettersss ps qsss gsss;

fun mk_flip (x, Type (_, [T1, Type (_, [T2, T3])])) =
  Abs ("x", T1, Abs ("y", T2, Var (x, T2 --> T1 --> T3) $ Bound 0 $ Bound 1));

fun flip_rels ctxt n thm =
  let
    val Rs = Term.add_vars (Thm.prop_of thm) [];
    val Rs' = rev (drop (length Rs - n) Rs);
  in
    infer_instantiate ctxt (map (fn f => (fst f, Thm.cterm_of ctxt (mk_flip f))) Rs') thm
  end;

fun mk_ctor_or_dtor get_T Ts t =
  let val Type (_, Ts0) = get_T (fastype_of t) in
    Term.subst_atomic_types (Ts0 ~~ Ts) t
  end;

val mk_ctor = mk_ctor_or_dtor range_type;
val mk_dtor = mk_ctor_or_dtor domain_type;

fun mk_bnf_sets bnf =
  let
    val Type (T_name, Us) = T_of_bnf bnf;
    val lives = lives_of_bnf bnf;
    val sets = sets_of_bnf bnf;
    fun mk_set U =
      (case find_index (curry (op =) U) lives of
        ~1 => Term.dummy
      | i => nth sets i);
  in
    (T_name, map mk_set Us)
  end;

fun mk_xtor_co_recs thy fp fpTs Cs ts0 =
  let
    val nn = length fpTs;
    val (fpTs0, Cs0) =
      map ((fp = Greatest_FP ? swap) o dest_funT o snd o strip_typeN nn o fastype_of) ts0
      |> split_list;
    val rho = tvar_subst thy (fpTs0 @ Cs0) (fpTs @ Cs);
  in
    map (Term.subst_TVars rho) ts0
  end;

fun liveness_of_fp_bnf n bnf =
  (case T_of_bnf bnf of
    Type (_, Ts) => map (not o member (op =) (deads_of_bnf bnf)) Ts
  | _ => replicate n false);

fun add_nesting_bnf_names Us =
  let
    fun add (Type (s, Ts)) ss =
        let val (needs, ss') = fold_map add Ts ss in
          if exists I needs then (true, insert (op =) s ss') else (false, ss')
        end
      | add T ss = (member (op =) Us T, ss);
  in snd oo add end;

fun nesting_bnfs ctxt ctr_Tsss Us =
  map_filter (bnf_of ctxt) (fold (fold (fold (add_nesting_bnf_names Us))) ctr_Tsss []);

fun indexify proj xs f p = f (find_index (curry (op =) (proj p)) xs) p;

fun massage_simple_notes base =
  filter_out (null o #2)
  #> map (fn (thmN, thms, f_attrs) =>
    ((Binding.qualify true base (Binding.name thmN), []),
     map_index (fn (i, thm) => ([thm], f_attrs i)) thms));

fun massage_multi_notes b_names Ts =
  maps (fn (thmN, thmss, attrs) =>
    @{map 3} (fn b_name => fn Type (T_name, _) => fn thms =>
        ((Binding.qualify true b_name (Binding.name thmN), attrs T_name), [(thms, [])]))
      b_names Ts thmss)
  #> filter_out (null o fst o hd o snd);

fun define_ctrs_dtrs_for_type fp_b_name fpT ctor dtor ctor_dtor dtor_ctor n ks abs ctr_bindings
    ctr_mixfixes ctr_Tss lthy =
  let
    val ctor_absT = domain_type (fastype_of ctor);

    val (((w, xss), u'), _) = lthy
      |> yield_singleton (mk_Frees "w") ctor_absT
      ||>> mk_Freess "x" ctr_Tss
      ||>> yield_singleton Variable.variant_fixes fp_b_name;

    val u = Free (u', fpT);

    val ctor_iff_dtor_thm =
      let
        val goal =
          fold_rev Logic.all [w, u]
            (mk_Trueprop_eq (HOLogic.mk_eq (u, ctor $ w), HOLogic.mk_eq (dtor $ u, w)));
        val vars = Variable.add_free_names lthy goal [];
      in
        Goal.prove_sorry lthy vars [] goal (fn {context = ctxt, ...} =>
          mk_ctor_iff_dtor_tac ctxt (map (SOME o Thm.ctyp_of lthy) [ctor_absT, fpT])
            (Thm.cterm_of lthy ctor) (Thm.cterm_of lthy dtor) ctor_dtor dtor_ctor)
        |> Thm.close_derivation \<^here>
      end;

    val ctr_rhss =
      map2 (fn k => fn xs => fold_rev Term.lambda xs (ctor $ mk_absumprod ctor_absT abs n k xs))
        ks xss;

    val ((raw_ctrs, raw_ctr_defs), (lthy, lthy_old)) = lthy
      |> (snd o Local_Theory.begin_nested)
      |> apfst split_list o @{fold_map 3} (fn b => fn mx => fn rhs =>
          Local_Theory.define ((b, mx),
            ((Thm.make_def_binding (Config.get lthy bnf_internals) b, []), rhs))
          #>> apsnd snd) ctr_bindings ctr_mixfixes ctr_rhss
      ||> `Local_Theory.end_nested;

    val phi = Proof_Context.export_morphism lthy_old lthy;

    val ctr_defs = map (Morphism.thm phi) raw_ctr_defs;
    val ctrs0 = map (Morphism.term phi) raw_ctrs;
  in
    ((xss, ctrs0, ctor_iff_dtor_thm, ctr_defs), lthy)
  end;

fun wrap_ctrs plugins fp discs_sels fp_b_name ctor_inject n ms abs_inject type_definition
    disc_bindings sel_bindingss sel_default_eqs ctrs0 ctor_iff_dtor_thm ctr_defs lthy =
  let
    val sumEN_thm' = unfold_thms lthy @{thms unit_all_eq1} (mk_absumprodE type_definition ms);

    fun exhaust_tac {context = ctxt, prems = _} =
      mk_exhaust_tac ctxt n ctr_defs ctor_iff_dtor_thm sumEN_thm';

    val inject_tacss =
      map2 (fn ctr_def => fn 0 => [] | _ => [fn {context = ctxt, ...} =>
        mk_inject_tac ctxt ctr_def ctor_inject abs_inject]) ctr_defs ms;

    val half_distinct_tacss =
      map (map (fn (def, def') => fn {context = ctxt, ...} =>
          mk_half_distinct_tac ctxt ctor_inject abs_inject [def, def']))
        (mk_half_pairss (`I ctr_defs));

    val tacss = [exhaust_tac] :: inject_tacss @ half_distinct_tacss;

    fun ctr_spec_of disc_b ctr0 sel_bs = ((disc_b, ctr0), sel_bs);
    val ctr_specs = @{map 3} ctr_spec_of disc_bindings ctrs0 sel_bindingss;

    val (ctr_sugar as {case_cong, ...}, lthy) =
      free_constructors (ctr_sugar_kind_of_fp_kind fp) tacss
        ((((plugins, discs_sels), standard_binding), ctr_specs), sel_default_eqs) lthy;

    val anonymous_notes =
      [([case_cong], fundefcong_attrs)]
      |> map (fn (thms, attrs) => ((Binding.empty, attrs), [(thms, [])]));

    val notes =
      if Config.get lthy bnf_internals then
        [(ctor_iff_dtorN, [ctor_iff_dtor_thm], K [])]
        |> massage_simple_notes fp_b_name
      else
        [];
  in
    (ctr_sugar, lthy |> Local_Theory.notes (anonymous_notes @ notes) |> snd)
  end;

fun derive_map_set_rel_pred_thms plugins fp live As Bs C E abs_inverses ctr_defs fp_nesting_set_maps
    fp_nesting_rel_eq_onps live_nesting_map_id0s live_nesting_set_maps live_nesting_rel_eqs
    live_nesting_rel_eq_onps fp_nested_rel_eq_onps fp_b_name fp_bnf fp_bnfs fpT ctor ctor_dtor
    dtor_ctor pre_map_def pre_set_defs pre_rel_def fp_map_thm fp_set_thms fp_rel_thm
    extra_unfolds_map extra_unfolds_set extra_unfolds_rel ctr_Tss
    ({casex, case_thms, discs, selss, sel_defs, ctrs, exhaust, exhaust_discs, disc_thmss, sel_thmss,
      injects, distincts, distinct_discsss, ...} : ctr_sugar)
    lthy =
  let
    val n = length ctr_Tss;
    val ms = map length ctr_Tss;

    val B_ify_T = Term.typ_subst_atomic (As ~~ Bs);

    val fpBT = B_ify_T fpT;
    val live_AsBs = filter (op <>) (As ~~ Bs);
    val live_As = map fst live_AsBs;
    val fTs = map (op -->) live_AsBs;

    val ((((((((xss, yss), fs), Ps), Rs), ta), tb), thesis), names_lthy) = lthy
      |> fold (fold Variable.declare_typ) [As, Bs]
      |> mk_Freess "x" ctr_Tss
      ||>> mk_Freess "y" (map (map B_ify_T) ctr_Tss)
      ||>> mk_Frees "f" fTs
      ||>> mk_Frees "P" (map mk_pred1T live_As)
      ||>> mk_Frees "R" (map (uncurry mk_pred2T) live_AsBs)
      ||>> yield_singleton (mk_Frees "a") fpT
      ||>> yield_singleton (mk_Frees "b") fpBT
      ||>> apfst HOLogic.mk_Trueprop o yield_singleton (mk_Frees "thesis") HOLogic.boolT;

    val ctrAs = map (mk_ctr As) ctrs;
    val ctrBs = map (mk_ctr Bs) ctrs;

    val ctr_defs' =
      map2 (fn m => fn def => mk_unabs_def m (HOLogic.mk_obj_eq def)) ms ctr_defs;

    val ABfs = live_AsBs ~~ fs;

    fun derive_rel_case relAsBs rel_inject_thms rel_distinct_thms =
      let
        val rel_Rs_a_b = list_comb (relAsBs, Rs) $ ta $ tb;

        fun mk_assms ctrA ctrB ctxt =
          let
            val argA_Ts = binder_types (fastype_of ctrA);
            val argB_Ts = binder_types (fastype_of ctrB);
            val ((argAs, argBs), names_ctxt) = ctxt
              |> mk_Frees "x" argA_Ts
              ||>> mk_Frees "y" argB_Ts;
            val ctrA_args = list_comb (ctrA, argAs);
            val ctrB_args = list_comb (ctrB, argBs);
          in
            (fold_rev Logic.all (argAs @ argBs) (Logic.list_implies
               (mk_Trueprop_eq (ta, ctrA_args) :: mk_Trueprop_eq (tb, ctrB_args) ::
                  map2 (HOLogic.mk_Trueprop oo build_rel_app lthy Rs []) argAs argBs,
                thesis)),
             names_ctxt)
          end;

        val (assms, names_lthy) = @{fold_map 2} mk_assms ctrAs ctrBs names_lthy;
        val goal = Logic.list_implies (HOLogic.mk_Trueprop rel_Rs_a_b :: assms, thesis);
      in
        Goal.prove_sorry lthy [] [] goal (fn {context = ctxt, prems = _} =>
          mk_rel_case_tac ctxt (Thm.cterm_of ctxt ta) (Thm.cterm_of ctxt tb) exhaust injects
            rel_inject_thms distincts rel_distinct_thms live_nesting_rel_eqs)
        |> singleton (Proof_Context.export names_lthy lthy)
        |> Thm.close_derivation \<^here>
      end;

    fun derive_case_transfer rel_case_thm =
      let
        val (S, names_lthy) = yield_singleton (mk_Frees "S") (mk_pred2T C E) names_lthy;
        val caseA = mk_case As C casex;
        val caseB = mk_case Bs E casex;
        val goal = mk_parametricity_goal names_lthy (S :: Rs) caseA caseB;
      in
        Goal.prove_sorry lthy [] [] goal (fn {context = ctxt, prems = _} =>
          mk_case_transfer_tac ctxt rel_case_thm case_thms)
        |> singleton (Proof_Context.export names_lthy lthy)
        |> Thm.close_derivation \<^here>
      end;
  in
    if live = 0 then
      if plugins transfer_plugin then
        let
          val relAsBs = HOLogic.eq_const fpT;
          val rel_case_thm = derive_rel_case relAsBs [] [];

          val case_transfer_thm = derive_case_transfer rel_case_thm;

          val notes =
            [(case_transferN, [case_transfer_thm], K [])]
            |> massage_simple_notes fp_b_name;

          val (noted, lthy') = lthy
            |> Local_Theory.notes notes;

          val subst = Morphism.thm (substitute_noted_thm noted);
        in
          (([], [], [], [], [], [], [], [], [], [], [], [], [], [], [subst case_transfer_thm], [],
            []), lthy')
        end
      else
        (([], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []), lthy)
    else
      let
        val mapx = mk_map live As Bs (map_of_bnf fp_bnf);
        val relAsBs = mk_rel live As Bs (rel_of_bnf fp_bnf);
        val setAs = map (mk_set As) (sets_of_bnf fp_bnf);
        val discAs = map (mk_disc_or_sel As) discs;
        val discBs = map (mk_disc_or_sel Bs) discs;
        val selAss = map (map (mk_disc_or_sel As)) selss;
        val selBss = map (map (mk_disc_or_sel Bs)) selss;

        val map_ctor_thm =
          if fp = Least_FP then
            fp_map_thm
          else
            let
              val ctorA = mk_ctor As ctor;
              val ctorB = mk_ctor Bs ctor;

              val y_T = domain_type (fastype_of ctorA);
              val (y as Free (y_s, _), _) = lthy
                |> yield_singleton (mk_Frees "y") y_T;

              val ctor_cong =
                infer_instantiate' lthy [NONE, NONE, SOME (Thm.cterm_of lthy ctorB)] arg_cong;
              val fp_map_thm' = fp_map_thm
                |> infer_instantiate' lthy (replicate live NONE @
                  [SOME (Thm.cterm_of lthy (ctorA $ y))])
                |> unfold_thms lthy [dtor_ctor];
            in
              (fp_map_thm' RS ctor_cong RS (ctor_dtor RS sym RS trans))
              |> Drule.generalize ([], [y_s])
            end;

        val map_thms =
          let
            fun mk_goal ctrA ctrB xs ys =
              let
                val fmap = list_comb (mapx, fs);

                fun mk_arg (x as Free (_, T)) (Free (_, U)) =
                  if T = U then x
                  else build_map lthy [] [] (the o AList.lookup (op =) ABfs) (T, U) $ x;

                val xs' = map2 mk_arg xs ys;
              in
                mk_Trueprop_eq (fmap $ list_comb (ctrA, xs), list_comb (ctrB, xs'))
              end;

            val goals = @{map 4} mk_goal ctrAs ctrBs xss yss;
            val goal = Logic.mk_conjunction_balanced goals;
            val vars = Variable.add_free_names lthy goal [];
          in
            Goal.prove_sorry lthy vars [] goal (fn {context = ctxt, prems = _} =>
              mk_map_tac ctxt abs_inverses pre_map_def map_ctor_thm live_nesting_map_id0s ctr_defs'
                extra_unfolds_map)
            |> Thm.close_derivation \<^here>
            |> Conjunction.elim_balanced (length goals)
          end;

        val set0_thms =
          let
            fun mk_goal A setA ctrA xs =
              let
                val sets = map (build_set_app lthy A)
                  (filter (exists_subtype_in [A] o fastype_of) xs);
              in
                mk_Trueprop_eq (setA $ list_comb (ctrA, xs),
                  (if null sets then HOLogic.mk_set A [] else Library.foldl1 mk_union sets))
              end;

            val goals =
              @{map 2} (fn live_A => fn setA => map2 (mk_goal live_A setA) ctrAs xss) live_As setAs
              |> flat;
          in
            if null goals then
              []
            else
              let
                val goal = Logic.mk_conjunction_balanced goals;
                val vars = Variable.add_free_names lthy goal [];
              in
                Goal.prove_sorry lthy vars [] goal (fn {context = ctxt, prems = _} =>
                  mk_set0_tac ctxt abs_inverses pre_set_defs dtor_ctor fp_set_thms
                    fp_nesting_set_maps live_nesting_set_maps ctr_defs' extra_unfolds_set)
                |> Thm.close_derivation \<^here>
                |> Conjunction.elim_balanced (length goals)
              end
          end;
        val set_thms = set0_thms
          |> map (unfold_thms lthy @{thms insert_is_Un[THEN sym] Un_empty_left Un_insert_left});

        val rel_ctor_thm =
          if fp = Least_FP then
            fp_rel_thm
          else
            let
              val ctorA = mk_ctor As ctor;
              val ctorB = mk_ctor Bs ctor;

              val y_T = domain_type (fastype_of ctorA);
              val z_T = domain_type (fastype_of ctorB);
              val ((y as Free (y_s, _), z as Free (z_s, _)), _) = lthy
                |> yield_singleton (mk_Frees "y") y_T
                ||>> yield_singleton (mk_Frees "z") z_T;
            in
              fp_rel_thm
              |> infer_instantiate' lthy (replicate live NONE @
                [SOME (Thm.cterm_of lthy (ctorA $ y)), SOME (Thm.cterm_of lthy (ctorB $ z))])
              |> unfold_thms lthy [dtor_ctor]
              |> Drule.generalize ([], [y_s, z_s])
            end;

        val rel_inject_thms =
          let
            fun mk_goal ctrA ctrB xs ys =
              let
                val lhs = list_comb (relAsBs, Rs) $ list_comb (ctrA, xs) $ list_comb (ctrB, ys);
                val conjuncts = map2 (build_rel_app lthy Rs []) xs ys;
              in
                HOLogic.mk_Trueprop
                  (if null conjuncts then lhs
                   else HOLogic.mk_eq (lhs, Library.foldr1 HOLogic.mk_conj conjuncts))
              end;

            val goals = @{map 4} mk_goal ctrAs ctrBs xss yss;
            val goal = Logic.mk_conjunction_balanced goals;
            val vars = Variable.add_free_names lthy goal [];
          in
            Goal.prove_sorry lthy vars [] goal (fn {context = ctxt, prems = _} =>
              mk_rel_tac ctxt abs_inverses pre_rel_def rel_ctor_thm live_nesting_rel_eqs ctr_defs'
                extra_unfolds_rel)
            |> Thm.close_derivation \<^here>
            |> Conjunction.elim_balanced (length goals)
          end;

        val half_rel_distinct_thmss =
          let
            fun mk_goal ((ctrA, xs), (ctrB, ys)) =
              HOLogic.mk_Trueprop (HOLogic.mk_not
                (list_comb (relAsBs, Rs) $ list_comb (ctrA, xs) $ list_comb (ctrB, ys)));

            val rel_infos = (ctrAs ~~ xss, ctrBs ~~ yss);

            val goalss = map (map mk_goal) (mk_half_pairss rel_infos);
            val goals = flat goalss;
          in
            unflat goalss
              (if null goals then
                 []
               else
                 let
                   val goal = Logic.mk_conjunction_balanced goals;
                   val vars = Variable.add_free_names lthy goal [];
                 in
                   Goal.prove_sorry lthy vars [] goal (fn {context = ctxt, prems = _} =>
                     mk_rel_tac ctxt abs_inverses pre_rel_def rel_ctor_thm live_nesting_rel_eqs
                       ctr_defs' extra_unfolds_rel)
                   |> Thm.close_derivation \<^here>
                   |> Conjunction.elim_balanced (length goals)
                 end)
          end;

        val rel_flip = rel_flip_of_bnf fp_bnf;

        fun mk_other_half_rel_distinct_thm thm =
          flip_rels lthy live thm RS (rel_flip RS sym RS @{thm arg_cong[of _ _ Not]} RS iffD2);

        val other_half_rel_distinct_thmss =
          map (map mk_other_half_rel_distinct_thm) half_rel_distinct_thmss;
        val (rel_distinct_thms, _) =
          join_halves n half_rel_distinct_thmss other_half_rel_distinct_thmss;

        fun mk_rel_intro_thm m thm =
          uncurry_thm m (thm RS iffD2) handle THM _ => thm;

        val rel_intro_thms = map2 mk_rel_intro_thm ms rel_inject_thms;

        val rel_code_thms =
          map (fn thm => thm RS @{thm eq_False[THEN iffD2]}) rel_distinct_thms @
          map2 (fn thm => fn 0 => thm RS @{thm eq_True[THEN iffD2]} | _ => thm) rel_inject_thms ms;

        val ctr_transfer_thms =
          let
            val goals = map2 (mk_parametricity_goal names_lthy Rs) ctrAs ctrBs;
            val goal = Logic.mk_conjunction_balanced goals;
            val vars = Variable.add_free_names lthy goal [];
          in
            Goal.prove_sorry lthy vars [] goal
              (fn {context = ctxt, prems = _} =>
                 mk_ctr_transfer_tac ctxt rel_intro_thms live_nesting_rel_eqs)
            |> Thm.close_derivation \<^here>
            |> Conjunction.elim_balanced (length goals)
          end;

        val (set_cases_thms, set_cases_attrss) =
          let
            fun mk_prems assms elem t ctxt =
              (case fastype_of t of
                Type (type_name, xs) =>
                (case bnf_of ctxt type_name of
                  NONE => ([], ctxt)
                | SOME bnf =>
                  apfst flat (fold_map (fn set => fn ctxt =>
                    let
                      val T = HOLogic.dest_setT (range_type (fastype_of set));
                      val new_var = not (T = fastype_of elem);
                      val (x, ctxt') =
                        if new_var then yield_singleton (mk_Frees "x") T ctxt else (elem, ctxt);
                    in
                      mk_prems (mk_Trueprop_mem (x, set $ t) :: assms) elem x ctxt'
                      |>> map (new_var ? Logic.all x)
                    end) (map (mk_set xs) (sets_of_bnf bnf)) ctxt))
              | T => rpair ctxt
                (if T = fastype_of elem then [fold (curry Logic.mk_implies) assms thesis] else []));
          in
            split_list (map (fn set =>
              let
                val A = HOLogic.dest_setT (range_type (fastype_of set));
                val (elem, names_lthy) = yield_singleton (mk_Frees "e") A names_lthy;
                val premss =
                  map (fn ctr =>
                    let
                      val (args, names_lthy) =
                        mk_Frees "z" (binder_types (fastype_of ctr)) names_lthy;
                    in
                      flat (zipper_map (fn (prev_args, arg, next_args) =>
                        let
                          val (args_with_elem, args_without_elem) =
                            if fastype_of arg = A then
                              (prev_args @ [elem] @ next_args, prev_args @ next_args)
                            else
                              `I (prev_args @ [arg] @ next_args);
                        in
                          mk_prems [mk_Trueprop_eq (ta, Term.list_comb (ctr, args_with_elem))]
                            elem arg names_lthy
                          |> fst
                          |> map (fold_rev Logic.all args_without_elem)
                        end) args)
                    end) ctrAs;
                val goal = Logic.mk_implies (mk_Trueprop_mem (elem, set $ ta), thesis);
                val vars = Variable.add_free_names lthy goal [];
                val thm =
                  Goal.prove_sorry lthy vars (flat premss) goal (fn {context = ctxt, prems} =>
                    mk_set_cases_tac ctxt (Thm.cterm_of ctxt ta) prems exhaust set_thms)
                  |> Thm.close_derivation \<^here>
                  |> rotate_prems ~1;

                val cases_set_attr =
                  Attrib.internal (K (Induct.cases_pred (name_of_set set)));

                val ctr_names = quasi_unambiguous_case_names (flat
                  (map (uncurry mk_names o map_prod length name_of_ctr) (premss ~~ ctrAs)));
              in
                (* TODO: @{attributes [elim?]} *)
                (thm, [Attrib.consumes 1, cases_set_attr, Attrib.case_names ctr_names])
              end) setAs)
          end;

        val (set_intros_thmssss, set_intros_thms) =
          let
            fun mk_goals A setA ctr_args t ctxt =
              (case fastype_of t of
                Type (type_name, innerTs) =>
                (case bnf_of ctxt type_name of
                  NONE => ([], ctxt)
                | SOME bnf =>
                  apfst flat (fold_map (fn set => fn ctxt =>
                    let
                      val T = HOLogic.dest_setT (range_type (fastype_of set));
                      val (y, ctxt') = yield_singleton (mk_Frees "y") T ctxt;
                      val assm = mk_Trueprop_mem (y, set $ t);
                    in
                      apfst (map (Logic.mk_implies o pair assm)) (mk_goals A setA ctr_args y ctxt')
                    end) (map (mk_set innerTs) (sets_of_bnf bnf)) ctxt))
              | T => (if T = A then [mk_Trueprop_mem (t, setA $ ctr_args)] else [], ctxt));

            val (goalssss, _) =
              fold_map (fn set =>
                let val A = HOLogic.dest_setT (range_type (fastype_of set)) in
                  @{fold_map 2} (fn ctr => fn xs =>
                      fold_map (mk_goals A set (Term.list_comb (ctr, xs))) xs)
                    ctrAs xss
                end) setAs lthy;
            val goals = flat (flat (flat goalssss));
          in
            `(unflattt goalssss)
              (if null goals then
                 []
               else
                 let
                   val goal = Logic.mk_conjunction_balanced goals;
                   val vars = Variable.add_free_names lthy goal [];
                 in
                   Goal.prove_sorry lthy vars [] goal
                     (fn {context = ctxt, prems = _} => mk_set_intros_tac ctxt set0_thms)
                   |> Thm.close_derivation \<^here>
                   |> Conjunction.elim_balanced (length goals)
                 end)
          end;

        val rel_sel_thms =
          let
            val n = length discAs;
            fun mk_conjunct n k discA selAs discB selBs =
              (if k = n then [] else [HOLogic.mk_eq (discA $ ta, discB $ tb)]) @
              (if null selAs then
                 []
               else
                 [Library.foldr HOLogic.mk_imp
                    (if n = 1 then [] else [discA $ ta, discB $ tb],
                     Library.foldr1 HOLogic.mk_conj (map2 (build_rel_app names_lthy Rs [])
                       (map (rapp ta) selAs) (map (rapp tb) selBs)))]);

            val goals =
              if n = 0 then
                []
              else
                [mk_Trueprop_eq (build_rel_app names_lthy Rs [] ta tb,
                   (case flat (@{map 5} (mk_conjunct n) (1 upto n) discAs selAss discBs selBss) of
                     [] => \<^term>\<open>True\<close>
                   | conjuncts => Library.foldr1 HOLogic.mk_conj conjuncts))];

            fun prove goal =
              Variable.add_free_names lthy goal []
              |> (fn vars => Goal.prove_sorry lthy vars [] goal (fn {context = ctxt, prems = _} =>
                mk_rel_sel_tac ctxt (Thm.cterm_of ctxt ta) (Thm.cterm_of ctxt tb) exhaust
                  (flat disc_thmss) (flat sel_thmss) rel_inject_thms distincts rel_distinct_thms
                  live_nesting_rel_eqs))
              |> Thm.close_derivation \<^here>;
          in
            map prove goals
          end;

        val (rel_case_thm, rel_case_attrs) =
          let
            val thm = derive_rel_case relAsBs rel_inject_thms rel_distinct_thms;
            val ctr_names = quasi_unambiguous_case_names (map name_of_ctr ctrAs);
          in
            (thm, [Attrib.case_names ctr_names, Attrib.consumes 1] @ @{attributes [cases pred]})
          end;

        val case_transfer_thm = derive_case_transfer rel_case_thm;

        val sel_transfer_thms =
          if null selAss then
            []
          else
            let
              val shared_sels = foldl1 (uncurry (inter (op =))) (map (op ~~) (selAss ~~ selBss));
              val goals = map (uncurry (mk_parametricity_goal names_lthy Rs)) shared_sels;
            in
              if null goals then
                []
              else
                let
                  val goal = Logic.mk_conjunction_balanced goals;
                  val vars = Variable.add_free_names lthy goal [];
                in
                  Goal.prove_sorry lthy vars [] goal
                    (fn {context = ctxt, prems = _} =>
                       mk_sel_transfer_tac ctxt n sel_defs case_transfer_thm)
                  |> Thm.close_derivation \<^here>
                  |> Conjunction.elim_balanced (length goals)
                end
            end;

        val disc_transfer_thms =
          let val goals = map2 (mk_parametricity_goal names_lthy Rs) discAs discBs in
            if null goals then
              []
            else
              let
                val goal = Logic.mk_conjunction_balanced goals;
                val vars = Variable.add_free_names lthy goal [];
              in
                Goal.prove_sorry lthy vars [] goal
                  (fn {context = ctxt, prems = _} => mk_disc_transfer_tac ctxt
                     (the_single rel_sel_thms) (the_single exhaust_discs)
                     (flat (flat distinct_discsss)))
                |> Thm.close_derivation \<^here>
                |> Conjunction.elim_balanced (length goals)
              end
          end;

        val map_disc_iff_thms =
          let
            val discsB = map (mk_disc_or_sel Bs) discs;
            val discsA_t = map (fn disc1 => Term.betapply (disc1, ta)) discAs;

            fun mk_goal (discA_t, discB) =
              if head_of discA_t aconv HOLogic.Not orelse is_refl_bool discA_t then
                NONE
              else
                SOME (mk_Trueprop_eq (betapply (discB, (Term.list_comb (mapx, fs) $ ta)), discA_t));

            val goals = map_filter mk_goal (discsA_t ~~ discsB);
          in
            if null goals then
              []
            else
              let
                val goal = Logic.mk_conjunction_balanced goals;
                val vars = Variable.add_free_names lthy goal [];
              in
                Goal.prove_sorry lthy vars [] goal
                  (fn {context = ctxt, prems = _} =>
                     mk_map_disc_iff_tac ctxt (Thm.cterm_of ctxt ta) exhaust (flat disc_thmss)
                       map_thms)
                |> Thm.close_derivation \<^here>
                |> Conjunction.elim_balanced (length goals)
              end
          end;

        val (map_sel_thmss, map_sel_thms) =
          let
            fun mk_goal discA selA selB =
              let
                val prem = Term.betapply (discA, ta);
                val lhs = selB $ (Term.list_comb (mapx, fs) $ ta);
                val lhsT = fastype_of lhs;
                val map_rhsT =
                  map_atyps (perhaps (AList.lookup (op =) (map swap live_AsBs))) lhsT;
                val map_rhs = build_map lthy [] []
                  (the o (AList.lookup (op =) (live_AsBs ~~ fs))) (map_rhsT, lhsT);
                val rhs = (case map_rhs of
                    Const (\<^const_name>\<open>id\<close>, _) => selA $ ta
                  | _ => map_rhs $ (selA $ ta));
                val concl = mk_Trueprop_eq (lhs, rhs);
              in
                if is_refl_bool prem then concl
                else Logic.mk_implies (HOLogic.mk_Trueprop prem, concl)
              end;

            val goalss = @{map 3} (map2 o mk_goal) discAs selAss selBss;
            val goals = flat goalss;
          in
            `(unflat goalss)
              (if null goals then
                 []
               else
                 let
                   val goal = Logic.mk_conjunction_balanced goals;
                   val vars = Variable.add_free_names lthy goal [];
                 in
                   Goal.prove_sorry lthy vars [] goal
                     (fn {context = ctxt, prems = _} =>
                        mk_map_sel_tac ctxt (Thm.cterm_of ctxt ta) exhaust (flat disc_thmss)
                          map_thms (flat sel_thmss) live_nesting_map_id0s)
                   |> Thm.close_derivation \<^here>
                   |> Conjunction.elim_balanced (length goals)
                 end)
          end;

        val (set_sel_thmssss, set_sel_thms) =
          let
            fun mk_goal setA discA selA ctxt =
              let
                val prem = Term.betapply (discA, ta);
                val sel_rangeT = range_type (fastype_of selA);
                val A = HOLogic.dest_setT (range_type (fastype_of setA));

                fun travese_nested_types t ctxt =
                  (case fastype_of t of
                    Type (type_name, innerTs) =>
                    (case bnf_of ctxt type_name of
                      NONE => ([], ctxt)
                    | SOME bnf =>
                      let
                        fun seq_assm a set ctxt =
                          let
                            val T = HOLogic.dest_setT (range_type (fastype_of set));
                            val (x, ctxt') = yield_singleton (mk_Frees "x") T ctxt;
                            val assm = mk_Trueprop_mem (x, set $ a);
                          in
                            travese_nested_types x ctxt'
                            |>> map (Logic.mk_implies o pair assm)
                          end;
                      in
                        fold_map (seq_assm t o mk_set innerTs) (sets_of_bnf bnf) ctxt
                        |>> flat
                      end)
                  | T =>
                    if T = A then ([mk_Trueprop_mem (t, setA $ ta)], ctxt) else ([], ctxt));

                val (concls, ctxt') =
                  if sel_rangeT = A then ([mk_Trueprop_mem (selA $ ta, setA $ ta)], ctxt)
                  else travese_nested_types (selA $ ta) ctxt;
              in
                if exists_subtype_in [A] sel_rangeT then
                  if is_refl_bool prem then (concls, ctxt')
                  else (map (Logic.mk_implies o pair (HOLogic.mk_Trueprop prem)) concls, ctxt')
                else
                  ([], ctxt)
              end;

            val (goalssss, _) =
              fold_map (fn set => @{fold_map 2} (fold_map o mk_goal set) discAs selAss)
                setAs names_lthy;
            val goals = flat (flat (flat goalssss));
          in
            `(unflattt goalssss)
              (if null goals then
                 []
               else
                 let
                   val goal = Logic.mk_conjunction_balanced goals;
                   val vars = Variable.add_free_names lthy goal [];
                 in
                   Goal.prove_sorry lthy vars [] goal
                     (fn {context = ctxt, prems = _} =>
                        mk_set_sel_tac ctxt (Thm.cterm_of ctxt ta) exhaust (flat disc_thmss)
                          (flat sel_thmss) set0_thms)
                   |> Thm.close_derivation \<^here>
                   |> Conjunction.elim_balanced (length goals)
                 end)
          end;

        val pred_injects =
          let
            fun top_sweep_rewr_conv rewrs =
              Conv.top_sweep_conv (K (Conv.rewrs_conv rewrs)) \<^context>;

            val rel_eq_onp_with_tops_of = Conv.fconv_rule (HOLogic.Trueprop_conv (Conv.arg1_conv
              (top_sweep_rewr_conv @{thms eq_onp_top_eq_eq[symmetric, THEN eq_reflection]})));

            val eq_onps = map rel_eq_onp_with_tops_of
              (map rel_eq_onp_of_bnf fp_bnfs @ fp_nesting_rel_eq_onps @ live_nesting_rel_eq_onps @
              fp_nested_rel_eq_onps);
            val cTs = map (SOME o Thm.ctyp_of lthy) (maps (replicate 2) live_As);
            val cts = map (SOME o Thm.cterm_of lthy) (map mk_eq_onp Ps);

            val get_rhs = Thm.concl_of #> HOLogic.dest_Trueprop #> HOLogic.dest_eq #> snd;

            val pred_eq_onp_conj =
              List.foldr (fn (_, thm) => thm RS @{thm eq_onp_live_step}) @{thm refl[of True]};

            fun predify_rel_inject rel_inject =
              let
                val conjuncts = try (get_rhs #> HOLogic.dest_conj) rel_inject |> the_default [];

                fun postproc thm =
                  if null conjuncts then
                    thm RS (@{thm eq_onp_same_args} RS iffD1)
                  else
                    @{thm box_equals} OF [thm, @{thm eq_onp_same_args},
                      pred_eq_onp_conj conjuncts |> unfold_thms lthy @{thms simp_thms(21)}];
              in
                rel_inject
                |> Thm.instantiate' cTs cts
                |> Conv.fconv_rule (HOLogic.Trueprop_conv (Conv.arg_conv
                  (Raw_Simplifier.rewrite lthy false
                     @{thms eq_onp_top_eq_eq[symmetric, THEN eq_reflection]})))
                |> unfold_thms lthy eq_onps
                |> postproc
                |> unfold_thms lthy @{thms top_conj}
              end;
          in
            rel_inject_thms
            |> map (unfold_thms lthy [@{thm conj_assoc}])
            |> map predify_rel_inject
            |> Proof_Context.export names_lthy lthy
          end;

        val anonymous_notes =
          [(rel_code_thms, nitpicksimp_attrs)]
          |> map (fn (thms, attrs) => ((Binding.empty, attrs), [(thms, [])]));

        val notes =
          (if Config.get lthy bnf_internals then
             [(set0N, set0_thms, K [])]
           else
             []) @
          [(case_transferN, [case_transfer_thm], K []),
           (ctr_transferN, ctr_transfer_thms, K []),
           (disc_transferN, disc_transfer_thms, K []),
           (sel_transferN, sel_transfer_thms, K []),
           (mapN, map_thms, K (nitpicksimp_attrs @ simp_attrs)),
           (map_disc_iffN, map_disc_iff_thms, K simp_attrs),
           (map_selN, map_sel_thms, K []),
           (pred_injectN, pred_injects, K simp_attrs),
           (rel_casesN, [rel_case_thm], K rel_case_attrs),
           (rel_distinctN, rel_distinct_thms, K simp_attrs),
           (rel_injectN, rel_inject_thms, K simp_attrs),
           (rel_introsN, rel_intro_thms, K []),
           (rel_selN, rel_sel_thms, K []),
           (setN, set_thms, K (case_fp fp nitpicksimp_attrs [] @ simp_attrs)),
           (set_casesN, set_cases_thms, nth set_cases_attrss),
           (set_introsN, set_intros_thms, K []),
           (set_selN, set_sel_thms, K [])]
          |> massage_simple_notes fp_b_name;

        val (noted, lthy') = lthy
          |> uncurry (Spec_Rules.add Binding.empty Spec_Rules.equational)
                (`(single o lhs_head_of o hd) map_thms)
          |> fp = Least_FP ?
              uncurry (Spec_Rules.add Binding.empty Spec_Rules.equational)
                (`(single o lhs_head_of o hd) rel_code_thms)
          |> uncurry (Spec_Rules.add Binding.empty Spec_Rules.equational)
                (`(single o lhs_head_of o hd) set0_thms)
          |> plugins code_plugin ? Code.declare_default_eqns (map (rpair true) (rel_code_thms @ map_thms @ set_thms))
          |> Local_Theory.notes (anonymous_notes @ notes);

        val subst = Morphism.thm (substitute_noted_thm noted);
      in
        ((map subst map_thms,
          map subst map_disc_iff_thms,
          map (map subst) map_sel_thmss,
          map subst rel_inject_thms,
          map subst rel_distinct_thms,
          map subst rel_sel_thms,
          map subst rel_intro_thms,
          [subst rel_case_thm],
          map subst pred_injects,
          map subst set_thms,
          map (map (map (map subst))) set_sel_thmssss,
          map (map (map (map subst))) set_intros_thmssss,
          map subst set_cases_thms,
          map subst ctr_transfer_thms,
          [subst case_transfer_thm],
          map subst disc_transfer_thms,
          map subst sel_transfer_thms), lthy')
      end
  end;

type lfp_sugar_thms = (thm list * thm * Token.src list) * (thm list list * Token.src list);

fun morph_lfp_sugar_thms phi ((inducts, induct, induct_attrs), (recss, rec_attrs)) =
  ((map (Morphism.thm phi) inducts, Morphism.thm phi induct, induct_attrs),
   (map (map (Morphism.thm phi)) recss, rec_attrs)) : lfp_sugar_thms;

val transfer_lfp_sugar_thms = morph_lfp_sugar_thms o Morphism.transfer_morphism;

type gfp_sugar_thms =
  ((thm list * thm) list * (Token.src list * Token.src list))
  * thm list list
  * thm list list
  * (thm list list * Token.src list)
  * (thm list list list * Token.src list);

fun morph_gfp_sugar_thms phi ((coinducts_pairs, coinduct_attrs_pair),
    corecss, corec_discss, (corec_disc_iffss, corec_disc_iff_attrs),
    (corec_selsss, corec_sel_attrs)) =
  ((map (apfst (map (Morphism.thm phi)) o apsnd (Morphism.thm phi)) coinducts_pairs,
    coinduct_attrs_pair),
   map (map (Morphism.thm phi)) corecss,
   map (map (Morphism.thm phi)) corec_discss,
   (map (map (Morphism.thm phi)) corec_disc_iffss, corec_disc_iff_attrs),
   (map (map (map (Morphism.thm phi))) corec_selsss, corec_sel_attrs)) : gfp_sugar_thms;

val transfer_gfp_sugar_thms = morph_gfp_sugar_thms o Morphism.transfer_morphism;

fun unzip_recT (Type (\<^type_name>\<open>prod\<close>, [_, TFree x]))
      (T as Type (\<^type_name>\<open>prod\<close>, Ts as [_, TFree y])) =
    if x = y then [T] else Ts
  | unzip_recT _ (Type (\<^type_name>\<open>prod\<close>, Ts as [_, TFree _])) = Ts
  | unzip_recT _ T = [T];

fun mk_recs_args_types ctxt ctr_Tsss Cs absTs repTs ns mss ctor_rec_fun_Ts =
  let
    val Css = map2 replicate ns Cs;
    val x_Tssss =
      @{map 6} (fn absT => fn repT => fn n => fn ms => fn ctr_Tss => fn ctor_rec_fun_T =>
          map2 (map2 unzip_recT)
            ctr_Tss (dest_absumprodT absT repT n ms (domain_type ctor_rec_fun_T)))
        absTs repTs ns mss ctr_Tsss ctor_rec_fun_Ts;

    val x_Tsss' = map (map flat_rec_arg_args) x_Tssss;
    val f_Tss = map2 (map2 (curry (op --->))) x_Tsss' Css;

    val ((fss, xssss), _) = ctxt
      |> mk_Freess "f" f_Tss
      ||>> mk_Freessss "x" x_Tssss;
  in
    (f_Tss, x_Tssss, fss, xssss)
  end;

fun unzip_corecT (Type (\<^type_name>\<open>sum\<close>, _)) T = [T]
  | unzip_corecT _ (Type (\<^type_name>\<open>sum\<close>, Ts)) = Ts
  | unzip_corecT _ T = [T];

(*avoid "'a itself" arguments in corecursors*)
fun repair_nullary_single_ctr [[]] = [[HOLogic.unitT]]
  | repair_nullary_single_ctr Tss = Tss;

fun mk_corec_fun_arg_types0 ctr_Tsss Cs absTs repTs ns mss fun_Ts =
  let
    val ctr_Tsss' = map repair_nullary_single_ctr ctr_Tsss;
    val g_absTs = map range_type fun_Ts;
    val g_Tsss =
      map repair_nullary_single_ctr (@{map 5} dest_absumprodT absTs repTs ns mss g_absTs);
    val g_Tssss = @{map 3} (fn C => map2 (map2 (map (curry (op -->) C) oo unzip_corecT)))
      Cs ctr_Tsss' g_Tsss;
    val q_Tssss = map (map (map (fn [_] => [] | [_, T] => [mk_pred1T (domain_type T)]))) g_Tssss;
  in
    (q_Tssss, g_Tsss, g_Tssss, g_absTs)
  end;

fun mk_corec_p_pred_types Cs ns = map2 (fn n => replicate (Int.max (0, n - 1)) o mk_pred1T) ns Cs;

fun mk_corec_fun_arg_types ctr_Tsss Cs absTs repTs ns mss dtor_corec =
  (mk_corec_p_pred_types Cs ns,
   mk_corec_fun_arg_types0 ctr_Tsss Cs absTs repTs ns mss
     (binder_fun_types (fastype_of dtor_corec)));

fun mk_corecs_args_types ctxt ctr_Tsss Cs absTs repTs ns mss dtor_corec_fun_Ts =
  let
    val p_Tss = mk_corec_p_pred_types Cs ns;

    val (q_Tssss, g_Tsss, g_Tssss, corec_types) =
      mk_corec_fun_arg_types0 ctr_Tsss Cs absTs repTs ns mss dtor_corec_fun_Ts;

    val (((((Free (x, _), cs), pss), qssss), gssss), _) = ctxt
      |> yield_singleton (mk_Frees "x") dummyT
      ||>> mk_Frees "a" Cs
      ||>> mk_Freess "p" p_Tss
      ||>> mk_Freessss "q" q_Tssss
--> --------------------

--> maximum size reached

--> --------------------

¤ Dauer der Verarbeitung: 0.89 Sekunden  (vorverarbeitet)  ¤





Download des
Quellennavigators
Download des
sprechenden Kalenders

in der Quellcodebibliothek suchen




Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.


Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.


Bot Zugriff