src/Pure/Isar/local_defs.ML
author boehmes
Wed, 12 May 2010 23:53:59 +0200
changeset 36895 a96f9793d9c5
parent 35739 35a3b3721ffb
child 39133 70d3915c92f0
permissions -rw-r--r--
split monolithic Z3 proof reconstruction structure into separate structures, use one set of schematic theorems for all uncertain proof rules (to extend proof reconstruction by missing cases), added several schematic theorems, improved abstraction of goals (abstract all uninterpreted sub-terms, only leave builtin symbols)

(*  Title:      Pure/Isar/local_defs.ML
    Author:     Makarius

Local definitions.
*)

signature LOCAL_DEFS =
sig
  val cert_def: Proof.context -> term -> (string * typ) * term
  val abs_def: term -> (string * typ) * term
  val mk_def: Proof.context -> (string * term) list -> term list
  val expand: cterm list -> thm -> thm
  val def_export: Assumption.export
  val add_defs: ((binding * mixfix) * (Thm.binding * term)) list -> Proof.context ->
    (term * (string * thm)) list * Proof.context
  val add_def: (binding * mixfix) * term -> Proof.context -> (term * thm) * Proof.context
  val fixed_abbrev: (binding * mixfix) * term -> Proof.context ->
    (term * term) * Proof.context
  val export: Proof.context -> Proof.context -> thm -> thm list * thm
  val export_cterm: Proof.context -> Proof.context -> cterm -> thm list * cterm
  val trans_terms: Proof.context -> thm list -> thm
  val trans_props: Proof.context -> thm list -> thm
  val contract: Proof.context -> thm list -> cterm -> thm -> thm
  val print_rules: Proof.context -> unit
  val defn_add: attribute
  val defn_del: attribute
  val meta_rewrite_conv: Proof.context -> conv
  val meta_rewrite_rule: Proof.context -> thm -> thm
  val unfold: Proof.context -> thm list -> thm -> thm
  val unfold_goals: Proof.context -> thm list -> thm -> thm
  val unfold_tac: Proof.context -> thm list -> tactic
  val fold: Proof.context -> thm list -> thm -> thm
  val fold_tac: Proof.context -> thm list -> tactic
  val derived_def: Proof.context -> bool -> term ->
    ((string * typ) * term) * (Proof.context -> thm -> thm)
end;

structure Local_Defs: LOCAL_DEFS =
struct

(** primitive definitions **)

(* prepare defs *)

fun cert_def ctxt eq =
  let
    fun err msg = cat_error msg ("The error(s) above occurred in definition: " ^
      quote (Syntax.string_of_term ctxt eq));
    val ((lhs, _), eq') = eq
      |> Sign.no_vars (Syntax.pp ctxt)
      |> Primitive_Defs.dest_def ctxt Term.is_Free (Variable.is_fixed ctxt) (K true)
      handle TERM (msg, _) => err msg | ERROR msg => err msg;
  in (Term.dest_Free (Term.head_of lhs), eq') end;

val abs_def = Primitive_Defs.abs_def #>> Term.dest_Free;

fun mk_def ctxt args =
  let
    val (xs, rhss) = split_list args;
    val (bind, _) = ProofContext.bind_fixes xs ctxt;
    val lhss = map (fn (x, rhs) => bind (Free (x, Term.fastype_of rhs))) args;
  in map Logic.mk_equals (lhss ~~ rhss) end;


(* export defs *)

val head_of_def =
  #1 o Term.dest_Free o Term.head_of o #1 o Logic.dest_equals o Term.strip_all_body;


(*
  [x, x == a]
       :
      B x
  -----------
      B a
*)
fun expand defs =
  Drule.implies_intr_list defs
  #> Drule.generalize ([], map (head_of_def o Thm.term_of) defs)
  #> funpow (length defs) (fn th => Drule.reflexive_thm RS th);

val expand_term = Envir.expand_term_frees o map (abs_def o Thm.term_of);

fun def_export _ defs = (expand defs, expand_term defs);


(* add defs *)

fun add_defs defs ctxt =
  let
    val ((bvars, mxs), specs) = defs |> split_list |>> split_list;
    val ((bfacts, atts), rhss) = specs |> split_list |>> split_list;
    val xs = map Name.of_binding bvars;
    val names = map2 Thm.def_binding_optional bvars bfacts;
    val eqs = mk_def ctxt (xs ~~ rhss);
    val lhss = map (fst o Logic.dest_equals) eqs;
  in
    ctxt
    |> ProofContext.add_fixes (map2 (fn x => fn mx => (x, NONE, mx)) bvars mxs) |> #2
    |> fold Variable.declare_term eqs
    |> ProofContext.add_assms_i def_export
      (map2 (fn a => fn eq => (a, [(eq, [])])) (names ~~ atts) eqs)
    |>> map2 (fn lhs => fn (name, [th]) => (lhs, (name, th))) lhss
  end;

fun add_def (var, rhs) ctxt =
  let val ([(lhs, (_, th))], ctxt') = add_defs [(var, (Thm.empty_binding, rhs))] ctxt
  in ((lhs, th), ctxt') end;


(* fixed_abbrev *)

fun fixed_abbrev ((x, mx), rhs) ctxt =
  let
    val T = Term.fastype_of rhs;
    val ([x'], ctxt') = ctxt
      |> Variable.declare_term rhs
      |> ProofContext.add_fixes [(x, SOME T, mx)];
    val lhs = Free (x', T);
    val _ = cert_def ctxt' (Logic.mk_equals (lhs, rhs));
    fun abbrev_export _ _ = (I, Envir.expand_term_frees [((x', T), rhs)]);
    val (_, ctxt'') = Assumption.add_assms abbrev_export [] ctxt';
  in ((lhs, rhs), ctxt'') end;


(* specific export -- result based on educated guessing *)

(*
  [xs, xs == as]
        :
       B xs
  --------------
       B as
*)
fun export inner outer =    (*beware of closure sizes*)
  let
    val exp = Assumption.export false inner outer;
    val prems = Assumption.all_prems_of inner;
  in fn th =>
    let
      val th' = exp th;
      val still_fixed = map #1 (Thm.fold_terms Term.add_frees th' []);
      val defs = prems |> filter_out (fn prem =>
        (case try (head_of_def o Thm.prop_of) prem of
          SOME x => member (op =) still_fixed x
        | NONE => true));
    in (map Drule.abs_def defs, th') end
  end;

(*
  [xs, xs == as]
        :
     TERM b xs
  --------------  and  --------------
     TERM b as          b xs == b as
*)
fun export_cterm inner outer ct =
  export inner outer (Drule.mk_term ct) ||> Drule.dest_term;


(* basic transitivity reasoning -- modulo beta-eta *)

local

val is_trivial = Pattern.aeconv o Logic.dest_equals o Thm.prop_of;

fun trans_list _ _ [] = raise Empty
  | trans_list trans ctxt (th :: raw_eqs) =
      (case filter_out is_trivial raw_eqs of
        [] => th
      | eqs =>
          let val ((_, th' :: eqs'), ctxt') = Variable.import true (th :: eqs) ctxt
          in singleton (Variable.export ctxt' ctxt) (fold trans eqs' th') end);

in

val trans_terms = trans_list (fn eq2 => fn eq1 => eq2 COMP (eq1 COMP Drule.transitive_thm));
val trans_props = trans_list (fn eq => fn th => th COMP (eq COMP Drule.equal_elim_rule1));

end;

fun contract ctxt defs ct th =
  trans_props ctxt [th, Thm.symmetric (MetaSimplifier.rewrite true defs ct)];


(** defived definitions **)

(* transformation rules *)

structure Rules = Generic_Data
(
  type T = thm list;
  val empty = [];
  val extend = I;
  val merge = Thm.merge_thms;
);

fun print_rules ctxt =
  Pretty.writeln (Pretty.big_list "definitional transformations:"
    (map (Display.pretty_thm ctxt) (Rules.get (Context.Proof ctxt))));

val defn_add = Thm.declaration_attribute (Rules.map o Thm.add_thm);
val defn_del = Thm.declaration_attribute (Rules.map o Thm.del_thm);


(* meta rewrite rules *)

fun meta_rewrite_conv ctxt =
  MetaSimplifier.rewrite_cterm (false, false, false) (K (K NONE))
    (MetaSimplifier.context ctxt MetaSimplifier.empty_ss
      addeqcongs [Drule.equals_cong]    (*protect meta-level equality*)
      addsimps (Rules.get (Context.Proof ctxt)));

val meta_rewrite_rule = Conv.fconv_rule o meta_rewrite_conv;


(* rewriting with object-level rules *)

fun meta f ctxt = f o map (meta_rewrite_rule ctxt);

val unfold       = meta MetaSimplifier.rewrite_rule;
val unfold_goals = meta MetaSimplifier.rewrite_goals_rule;
val unfold_tac   = meta MetaSimplifier.rewrite_goals_tac;
val fold         = meta MetaSimplifier.fold_rule;
val fold_tac     = meta MetaSimplifier.fold_goals_tac;


(* derived defs -- potentially within the object-logic *)

fun derived_def ctxt conditional prop =
  let
    val ((c, T), rhs) = prop
      |> Thm.cterm_of (ProofContext.theory_of ctxt)
      |> meta_rewrite_conv ctxt
      |> (snd o Logic.dest_equals o Thm.prop_of)
      |> conditional ? Logic.strip_imp_concl
      |> (abs_def o #2 o cert_def ctxt);
    fun prove ctxt' def =
      let
        val frees = Term.fold_aterms (fn Free (x, _) =>
          if Variable.is_fixed ctxt' x then I else insert (op =) x | _ => I) prop [];
      in
        Goal.prove ctxt' frees [] prop (K (ALLGOALS
          (CONVERSION (meta_rewrite_conv ctxt') THEN'
            MetaSimplifier.rewrite_goal_tac [def] THEN'
            resolve_tac [Drule.reflexive_thm])))
        handle ERROR msg => cat_error msg "Failed to prove definitional specification."
      end;
  in (((c, T), rhs), prove) end;

end;