Proper rewrite morphisms in locale instances.
authorballarin
Fri, 02 Mar 2018 14:19:25 +0100
changeset 67740 b6ce18784872
parent 67739 e512938b853c
child 67741 d5a7f2c54655
Proper rewrite morphisms in locale instances.
NEWS
src/Doc/Isar_Ref/Spec.thy
src/FOL/ex/Locale_Test/Locale_Test1.thy
src/Pure/Isar/element.ML
src/Pure/Isar/expression.ML
src/Pure/Isar/interpretation.ML
src/Pure/Isar/parse_spec.ML
src/Pure/Pure.thy
--- a/NEWS	Thu Mar 01 20:44:38 2018 +0100
+++ b/NEWS	Fri Mar 02 14:19:25 2018 +0100
@@ -175,6 +175,11 @@
 Rare INCOMPATIBILITY, need to refer to explicitly named facts instead
 (e.g. use 'find_theorems' or 'try' to figure this out).
 
+* Rewrites clauses (keyword 'rewrites') were moved into the locale
+expression syntax, where they are part of locale instances.  Keyword
+'for' now needs to occur after, not before 'rewrites'.
+Minor INCOMPATIBILITY.
+
 
 *** Pure ***
 
--- a/src/Doc/Isar_Ref/Spec.thy	Thu Mar 01 20:44:38 2018 +0100
+++ b/src/Doc/Isar_Ref/Spec.thy	Fri Mar 02 14:19:25 2018 +0100
@@ -460,17 +460,20 @@
   @{rail \<open>
     @{syntax_def locale_expr}: (instance + '+') @{syntax for_fixes}
     ;
-    instance: (qualifier ':')? @{syntax name} (pos_insts | named_insts)
+    instance: (qualifier ':')? @{syntax name} (pos_insts | named_insts) rewrites?
     ;
     qualifier: @{syntax name} ('?')?
     ;
     pos_insts: ('_' | @{syntax term})*
     ;
     named_insts: @'where' (@{syntax name} '=' @{syntax term} + @'and')
+    ;
+    rewrites: @'rewrites' (@{syntax thmdecl}? @{syntax prop} + @'and')
   \<close>}
 
   A locale instance consists of a reference to a locale and either positional
-  or named parameter instantiations. Identical instantiations (that is, those
+  or named parameter instantiations optionally followed by rewrites clauses.
+  Identical instantiations (that is, those
   that instantiate a parameter by itself) may be omitted. The notation ``\<open>_\<close>''
   enables to omit the instantiation for a parameter inside a positional
   instantiation.
@@ -487,6 +490,11 @@
   ``\<^verbatim>\<open>?\<close>''). Non-mandatory means that the qualifier may be omitted on input.
   Qualifiers only affect name spaces; they play no role in determining whether
   one locale instance subsumes another.
+
+  Rewrite clauses amend instances with equations that act as rewrite rules.
+  This is particularly useful for changing concepts introduced through
+  definitions. Rewrite clauses are available only in interpretation commands
+  (see \secref{sec:locale-interpretation} below) and must be proved the user.
 \<close>
 
 
@@ -622,7 +630,7 @@
 \<close>
 
 
-subsection \<open>Locale interpretation\<close>
+subsection \<open>Locale interpretation \label{sec:locale-interpretation}\<close>
 
 text \<open>
   \begin{matharray}{rcl}
@@ -642,15 +650,15 @@
   into locales (\<^theory_text>\<open>sublocale\<close>).
 
   @{rail \<open>
-    @@{command interpretation} @{syntax locale_expr} equations?
+    @@{command interpretation} @{syntax locale_expr}
     ;
-    @@{command interpret} @{syntax locale_expr} equations?
+    @@{command interpret} @{syntax locale_expr}
     ;
     @@{command global_interpretation} @{syntax locale_expr} \<newline>
-      definitions? equations?
+      (definitions rewrites?)?
     ;
     @@{command sublocale} (@{syntax name} ('<' | '\<subseteq>'))? @{syntax locale_expr} \<newline>
-      definitions? equations?
+      (definitions rewrites?)?
     ;
     @@{command print_dependencies} '!'? @{syntax locale_expr}
     ;
@@ -659,8 +667,6 @@
 
     definitions: @'defines' (@{syntax thmdecl}? @{syntax name} \<newline>
       @{syntax mixfix}? @'=' @{syntax term} + @'and');
-
-    equations: @'rewrites' (@{syntax thmdecl}? @{syntax prop} + @'and')
   \<close>}
 
   The core of each interpretation command is a locale expression \<open>expr\<close>; the
@@ -675,13 +681,14 @@
   to simplify the proof obligations according to existing interpretations use
   methods @{method intro_locales} or @{method unfold_locales}.
 
-  Given equations \<open>eqns\<close> amend the morphism through which \<open>expr\<close> is
-  interpreted, adding rewrite rules. This is particularly useful for
-  interpreting concepts introduced through definitions. The equations must be
-  proved the user.
+  Rewrites clauses \<^theory_text>\<open>rewrites eqns\<close> can occur within expressions or, for
+  some commands, as part of the command itself.  They amend the morphism
+  through which a locale instance or expression \<open>expr\<close> is interpreted with
+  rewrite rules. This is particularly useful for interpreting concepts
+  introduced through definitions. The equations must be proved the user.
 
   Given definitions \<open>defs\<close> produce corresponding definitions in the local
-  theory's underlying target \<^emph>\<open>and\<close> amend the morphism with the equations
+  theory's underlying target \<^emph>\<open>and\<close> amend the morphism with rewrite rules
   stemming from the symmetric of those definitions. Hence these need not be
   proved explicitly the user. Such rewrite definitions are a even more useful
   device for interpreting concepts introduced through definitions, but they
@@ -690,7 +697,7 @@
   the suggestive \<^theory_text>\<open>and\<close> connective, \<open>defs\<close>
   are processed sequentially without mutual recursion.
 
-  \<^descr> \<^theory_text>\<open>interpretation expr rewrites eqns\<close> interprets \<open>expr\<close> into a local theory
+  \<^descr> \<^theory_text>\<open>interpretation expr\<close> interprets \<open>expr\<close> into a local theory
   such that its lifetime is limited to the current context block (e.g. a
   locale or unnamed context). At the closing @{command end} of the block the
   interpretation and its declarations disappear. Hence facts based on
@@ -702,7 +709,7 @@
   context block, hence \<^theory_text>\<open>interpretation\<close> behaves identically to
   \<^theory_text>\<open>global_interpretation\<close> then.
 
-  \<^descr> \<^theory_text>\<open>interpret expr rewrites eqns\<close> interprets \<open>expr\<close> into a proof context:
+  \<^descr> \<^theory_text>\<open>interpret expr\<close> interprets \<open>expr\<close> into a proof context:
   the interpretation and its declarations disappear when closing the current
   proof block. Note that for \<^theory_text>\<open>interpret\<close> the \<open>eqns\<close> should be explicitly
   universally quantified.
@@ -720,7 +727,7 @@
   free variable whose name is already bound in the context --- for example,
   because a constant of that name exists --- add it to the \<^theory_text>\<open>for\<close> clause.
 
-  \<^descr> \<^theory_text>\<open>sublocale name \<subseteq> defines defs expr rewrites eqns\<close> interprets \<open>expr\<close>
+  \<^descr> \<^theory_text>\<open>sublocale name \<subseteq> expr defines defs rewrites eqns\<close> interprets \<open>expr\<close>
   into the locale \<open>name\<close>. A proof that the specification of \<open>name\<close> implies the
   specification of \<open>expr\<close> is required. As in the localized version of the
   theorem command, the proof is in the context of \<open>name\<close>. After the proof
@@ -737,8 +744,8 @@
   adds interpretations for \<open>expr\<close> as well, with the same qualifier, although
   only for fragments of \<open>expr\<close> that are not interpreted in the theory already.
 
-  Using equations \<open>eqns\<close> or rewrite definitions \<open>defs\<close> can help break infinite
-  chains induced by circular \<^theory_text>\<open>sublocale\<close> declarations.
+  Using rewrite rules \<open>eqns\<close> or rewrite definitions \<open>defs\<close> can help break
+  infinite chains induced by circular \<^theory_text>\<open>sublocale\<close> declarations.
 
   In a named context block the \<^theory_text>\<open>sublocale\<close> command may also be used, but the
   locale argument must be omitted. The command then refers to the locale (or
--- a/src/FOL/ex/Locale_Test/Locale_Test1.thy	Thu Mar 01 20:44:38 2018 +0100
+++ b/src/FOL/ex/Locale_Test/Locale_Test1.thy	Fri Mar 02 14:19:25 2018 +0100
@@ -523,7 +523,7 @@
 
 subsection \<open>Rewrite morphisms in expressions\<close>
 
-interpretation y: logic_o "(\<or>)" "Not" replaces bool_logic_o2: "logic_o.lor_o((\<or>), Not, x, y) \<longleftrightarrow> x \<and> y"
+interpretation y: logic_o "(\<or>)" "Not" rewrites bool_logic_o2: "logic_o.lor_o((\<or>), Not, x, y) \<longleftrightarrow> x \<and> y"
 proof -
   show bool_logic_o: "PROP logic_o((\<or>), Not)" by unfold_locales fast+
   show "logic_o.lor_o((\<or>), Not, x, y) \<longleftrightarrow> x \<and> y" unfolding logic_o.lor_o_def [OF bool_logic_o] by fast
--- a/src/Pure/Isar/element.ML	Thu Mar 01 20:44:38 2018 +0100
+++ b/src/Pure/Isar/element.ML	Fri Mar 02 14:19:25 2018 +0100
@@ -50,6 +50,7 @@
   val instantiate_normalize_morphism:
     ((string * sort) * ctyp) list * ((string * typ) * cterm) list -> morphism
   val satisfy_morphism: witness list -> morphism
+  val eq_term_morphism: theory -> term list -> morphism option
   val eq_morphism: theory -> thm list -> morphism option
   val init: context_i -> Context.generic -> Context.generic
   val activate_i: context_i -> Proof.context -> context_i * Proof.context
@@ -381,6 +382,26 @@
 
 (* rewriting with equalities *)
 
+(* for activating declarations only *)
+fun eq_term_morphism _ [] = NONE
+  | eq_term_morphism thy props =
+      let
+        fun decomp_simp prop =
+          let
+            val ctxt = Proof_Context.init_global thy;
+            val _ = Logic.count_prems prop = 0 orelse
+              error ("Bad conditional rewrite rule " ^ Syntax.string_of_term ctxt prop);
+            val lhsrhs = Logic.dest_equals prop
+              handle TERM _ => error ("Rewrite rule not a meta-equality " ^ Syntax.string_of_term ctxt prop);
+          in lhsrhs end;
+        val phi =
+          Morphism.morphism "Element.eq_term_morphism"
+           {binding = [],
+            typ = [],
+            term = [Pattern.rewrite_term thy (map decomp_simp props) []],
+            fact = [fn _ => error "Illegal application of Element.eq_term_morphism"]};
+      in SOME phi end;
+
 fun eq_morphism _ [] = NONE
   | eq_morphism thy thms =
       let
--- a/src/Pure/Isar/expression.ML	Thu Mar 01 20:44:38 2018 +0100
+++ b/src/Pure/Isar/expression.ML	Fri Mar 02 14:19:25 2018 +0100
@@ -8,7 +8,8 @@
 sig
   (* Locale expressions *)
   datatype 'term map = Positional of 'term option list | Named of (string * 'term) list
-  type ('name, 'term) expr = ('name * ((string * bool) * ('term map * (Attrib.binding * 'term) list))) list
+  type 'term rewrites = (Attrib.binding * 'term) list
+  type ('name, 'term) expr = ('name * ((string * bool) * ('term map * 'term rewrites))) list
   type expression_i = (string, term) expr * (binding * typ option * mixfix) list
   type expression = (xstring * Position.T, string) expr * (binding * string option * mixfix) list
 
@@ -58,7 +59,9 @@
   Positional of 'term option list |
   Named of (string * 'term) list;
 
-type ('name, 'term) expr = ('name * ((string * bool) * ('term map * (Attrib.binding * 'term) list))) list;
+type 'term rewrites = (Attrib.binding * 'term) list;
+
+type ('name, 'term) expr = ('name * ((string * bool) * ('term map * 'term rewrites))) list;
 
 type expression_i = (string, term) expr * (binding * typ option * mixfix) list;
 type expression = (xstring * Position.T, string) expr * (binding * string option * mixfix) list;
@@ -367,8 +370,11 @@
 
 local
 
+fun abs_def ctxt =
+  Thm.cterm_of ctxt #> Assumption.assume ctxt #> Local_Defs.abs_def_rule ctxt #> Thm.prop_of;
+
 fun prep_full_context_statement
-    parse_typ parse_prop prep_obtains prep_var_elem prep_inst parse_eqn prep_var_inst prep_expr
+    parse_typ parse_prop prep_obtains prep_var_elem prep_inst prep_eqns prep_attr prep_var_inst prep_expr
     {strict, do_close, fixed_frees} raw_import init_body raw_elems raw_stmt ctxt1 =
   let
     val thy = Proof_Context.theory_of ctxt1;
@@ -379,23 +385,29 @@
       let
         val params = map #1 (Locale.params_of thy loc);
         val inst' = prep_inst ctxt (map #1 params) inst;
-        val eqns' = map (apsnd (parse_eqn ctxt)) eqns;
         val parm_types' =
           params |> map (#2 #> Logic.varifyT_global #>
               Term.map_type_tvar (fn ((x, _), S) => TVar ((x, i), S)) #>
               Type_Infer.paramify_vars);
         val inst'' = map2 Type.constraint parm_types' inst';
         val insts' = insts @ [(loc, (prfx, inst''))];
-        val eqnss' = eqnss @ [eqns'];
-        val ((insts'', eqnss'', _, _), _) = check_autofix insts' eqnss' [] [] ctxt;
-        val (inst_morph, _) = inst_morphism params (prfx, #2 (#2 (List.last insts''))) ctxt;
-        val rewrite_morph =
-          List.last eqnss''
-          |> map (snd #> Thm.cterm_of ctxt #> Thm.assume #> Local_Defs.abs_def_rule ctxt)
-          |> Element.eq_morphism (Proof_Context.theory_of ctxt)
+        val ((insts'', _, _, _), ctxt2) = check_autofix insts' [] [] [] ctxt;
+        val inst''' = insts'' |> List.last |> snd |> snd;
+        val (inst_morph, _) = inst_morphism params (prfx, inst''') ctxt;
+        val ctxt' = Locale.activate_declarations (loc, inst_morph) ctxt2; (* may fail *)
+
+        val attrss = map (apsnd (map (prep_attr ctxt)) o fst) eqns;
+        val eqns' = (prep_eqns ctxt' o map snd) eqns;
+        val eqnss' = [attrss ~~ eqns'];
+        val ((_, [eqns''], _, _), _) = check_autofix insts'' eqnss' [] [] ctxt';
+        val rewrite_morph = eqns'
+          |> map (abs_def ctxt')
+          |> Variable.export_terms ctxt' ctxt
+          |> Element.eq_term_morphism (Proof_Context.theory_of ctxt)
           |> the_default Morphism.identity;
-        val ctxt' = Locale.activate_declarations (loc, inst_morph $> rewrite_morph) ctxt;
-      in (i + 1, insts', eqnss', ctxt') end;
+       val ctxt'' = Locale.activate_declarations (loc, inst_morph $> rewrite_morph) ctxt;
+       val eqnss' = eqnss @ [attrss ~~ Variable.export_terms ctxt' ctxt eqns'];
+      in (i + 1, insts', eqnss', ctxt'') end;
 
     fun prep_elem raw_elem ctxt =
       let
@@ -411,7 +423,7 @@
     val (_, insts', eqnss', ctxt3) = fold prep_insts_cumulative raw_insts (0, [], [], ctxt2);
 
     fun prep_stmt elems ctxt =
-      check_autofix insts' eqnss' elems (prepare_stmt parse_prop prep_obtains ctxt raw_stmt) ctxt;
+      check_autofix insts' [] elems (prepare_stmt parse_prop prep_obtains ctxt raw_stmt) ctxt;
 
     val _ =
       if fixed_frees then ()
@@ -421,7 +433,7 @@
         | frees => error ("Illegal free variables in expression: " ^
             commas_quote (map (Syntax.string_of_term ctxt3 o Free) (rev frees))));
 
-    val ((insts, eqnss, elems', concl), ctxt4) = ctxt3
+    val ((insts, _, elems', concl), ctxt4) = ctxt3
       |> init_body
       |> fold_map prep_elem raw_elems
       |-> prep_stmt;
@@ -438,21 +450,21 @@
     val deps = map (finish_inst ctxt5) insts;
     val elems'' = map (finish_elem (ctxt1, ctxt5) parms do_close) elems';
 
-  in ((fixed, deps, eqnss, elems'', concl), (parms, ctxt5)) end;
+  in ((fixed, deps, eqnss', elems'', concl), (parms, ctxt5)) end;
 
 in
 
 fun cert_full_context_statement x =
   prep_full_context_statement (K I) (K I) Obtain.cert_obtains
-    Proof_Context.cert_var make_inst (K I) Proof_Context.cert_var (K I) x;
+    Proof_Context.cert_var make_inst Syntax.check_props (K I) Proof_Context.cert_var (K I) x;
 
 fun cert_read_full_context_statement x =
   prep_full_context_statement Syntax.parse_typ Syntax.parse_prop Obtain.parse_obtains
-    Proof_Context.read_var make_inst (K I) Proof_Context.cert_var (K I) x;
+    Proof_Context.read_var make_inst Syntax.check_props (K I) Proof_Context.cert_var (K I) x;
 
 fun read_full_context_statement x =
   prep_full_context_statement Syntax.parse_typ Syntax.parse_prop Obtain.parse_obtains
-    Proof_Context.read_var parse_inst (Syntax.parse_prop) Proof_Context.read_var check_expr x;
+    Proof_Context.read_var parse_inst Syntax.read_props Attrib.check_src Proof_Context.read_var check_expr x;
 
 end;
 
@@ -492,7 +504,7 @@
     val ((fixed, deps, eqnss, elems, _), (parms, ctxt0)) =
       prep {strict = false, do_close = true, fixed_frees = false}
         raw_import init_body raw_elems (Element.Shows []) ctxt;
-    val _ = null (flat eqnss) orelse error "Illegal replaces clause(s) in declaration of locale";
+    val _ = null (flat eqnss) orelse error "Illegal rewrites clause(s) in declaration of locale";
     (* Declare parameters and imported facts *)
     val ctxt' = ctxt
       |> fix_params fixed
@@ -537,7 +549,7 @@
 
     val goal_ctxt = ctxt
       |> fix_params fixed
-      |> (fold o fold) Variable.auto_fixes propss;
+      |> (fold o fold) Variable.auto_fixes (propss @ eq_propss);
 
     val export = Variable.export_morphism goal_ctxt ctxt;
     val exp_fact = Drule.zero_var_indexes_list o map Thm.strip_shyps o Morphism.fact export;
--- a/src/Pure/Isar/interpretation.ML	Thu Mar 01 20:44:38 2018 +0100
+++ b/src/Pure/Isar/interpretation.ML	Fri Mar 02 14:19:25 2018 +0100
@@ -49,7 +49,7 @@
 (** common interpretation machinery **)
 
 type 'a defines = (Attrib.binding * ((binding * mixfix) * 'a)) list
-type 'a rewrites = (Attrib.binding * 'a) list
+type 'a rewrites = 'a Expression.rewrites
 
 (* reading of locale expressions with rewrite morphisms *)
 
@@ -83,7 +83,7 @@
   | prep_eqns prep_props prep_attr raw_eqns deps ctxt =
       let
         (* FIXME incompatibility, creating context for parsing rewrites equation may fail in
-           presence of replaces clause *)
+           presence of rewrites clause in expression *)
         val ctxt' = fold Locale.activate_declarations deps ctxt;
         val eqns =
           (Variable.export_terms ctxt' ctxt o prep_props ctxt' o map snd) raw_eqns;
--- a/src/Pure/Isar/parse_spec.ML	Thu Mar 01 20:44:38 2018 +0100
+++ b/src/Pure/Isar/parse_spec.ML	Fri Mar 02 14:19:25 2018 +0100
@@ -114,7 +114,7 @@
 val instance = Scan.optional (Parse.where_ |--
   Parse.and_list1 (Parse.name -- (Parse.$$$ "=" |-- Parse.term)) >> Expression.Named ||
   Scan.repeat1 (Parse.maybe Parse.term) >> Expression.Positional) (Expression.Named []) --
-  (Scan.optional (Parse.$$$ "replaces" |-- Parse.and_list1 (opt_thm_name ":" -- Parse.prop)) []);
+  (Scan.optional (Parse.$$$ "rewrites" |-- Parse.and_list1 (opt_thm_name ":" -- Parse.prop)) []);
 
 in
 
--- a/src/Pure/Pure.thy	Thu Mar 01 20:44:38 2018 +0100
+++ b/src/Pure/Pure.thy	Fri Mar 02 14:19:25 2018 +0100
@@ -10,7 +10,7 @@
     "\<subseteq>" "]" "attach" "binder" "in" "infix" "infixl" "infixr" "is" "open" "output"
     "overloaded" "pervasive" "premises" "structure" "unchecked"
   and "private" "qualified" :: before_command
-  and "assumes" "constrains" "defines" "fixes" "for" "if" "includes" "notes" "replaces" "rewrites"
+  and "assumes" "constrains" "defines" "fixes" "for" "if" "includes" "notes" "rewrites"
     "obtains" "shows" "when" "where" "|" :: quasi_command
   and "text" "txt" :: document_body
   and "text_raw" :: document_raw
@@ -613,23 +613,18 @@
       >> (fn elems =>
           Toplevel.begin_local_theory true (Experiment.experiment_cmd elems #> snd)));
 
-val interpretation_args =
-  Parse.!!! Parse_Spec.locale_expression --
-    Scan.optional
-      (\<^keyword>\<open>rewrites\<close> |-- Parse.and_list1 (Parse_Spec.opt_thm_name ":" -- Parse.prop)) [];
-
 val _ =
   Outer_Syntax.command \<^command_keyword>\<open>interpret\<close>
     "prove interpretation of locale expression in proof context"
-    (interpretation_args >> (fn (expr, equations) =>
-      Toplevel.proof (Interpretation.interpret_cmd expr equations)));
+    (Parse.!!! Parse_Spec.locale_expression >> (fn expr =>
+      Toplevel.proof (Interpretation.interpret_cmd expr [])));
 
 val interpretation_args_with_defs =
   Parse.!!! Parse_Spec.locale_expression --
     (Scan.optional (\<^keyword>\<open>defines\<close> |-- Parse.and_list1 (Parse_Spec.opt_thm_name ":"
-      -- ((Parse.binding -- Parse.opt_mixfix') --| \<^keyword>\<open>=\<close> -- Parse.term))) [] --
-    Scan.optional
-      (\<^keyword>\<open>rewrites\<close> |-- Parse.and_list1 (Parse_Spec.opt_thm_name ":" -- Parse.prop)) []);
+      -- ((Parse.binding -- Parse.opt_mixfix') --| \<^keyword>\<open>=\<close> -- Parse.term))
+      -- Scan.optional (\<^keyword>\<open>rewrites\<close> |-- Parse.and_list1 (Parse_Spec.opt_thm_name ":"
+        -- Parse.prop)) []) ([], []));
 
 val _ =
   Outer_Syntax.local_theory_to_proof \<^command_keyword>\<open>global_interpretation\<close>
@@ -649,9 +644,9 @@
 val _ =
   Outer_Syntax.command \<^command_keyword>\<open>interpretation\<close>
     "prove interpretation of locale expression in local theory or into global theory"
-    (interpretation_args >> (fn (expr, equations) =>
+    (Parse.!!! Parse_Spec.locale_expression >> (fn expr =>
       Toplevel.local_theory_to_proof NONE NONE
-        (Interpretation.isar_interpretation_cmd expr equations)));
+        (Interpretation.isar_interpretation_cmd expr [])));
 
 in end\<close>