| 20856 |      1 | (*  Title:      Pure/nbe.ML
 | 
|  |      2 |     ID:         $Id$
 | 
| 19147 |      3 |     Author:     Tobias Nipkow, Florian Haftmann, TU Muenchen
 | 
|  |      4 | 
 | 
| 19177 |      5 | Toplevel theory interface for "normalization by evaluation"
 | 
| 19147 |      6 | *)
 | 
|  |      7 | 
 | 
| 19177 |      8 | signature NBE =
 | 
| 19147 |      9 | sig
 | 
| 20856 |     10 |   (*preconditions: no Vars/TVars in term*)
 | 
| 19962 |     11 |   val norm_term: theory -> term -> term
 | 
| 20602 |     12 |   val normalization_conv: cterm -> thm
 | 
| 19962 |     13 |   val lookup: string -> NBE_Eval.Univ
 | 
| 19795 |     14 |   val update: string * NBE_Eval.Univ -> unit
 | 
| 20846 |     15 |   val trace: bool ref
 | 
| 19147 |     16 | end;
 | 
|  |     17 | 
 | 
| 19177 |     18 | structure NBE: NBE =
 | 
| 19147 |     19 | struct
 | 
|  |     20 | 
 | 
| 20846 |     21 | val trace = ref false;
 | 
|  |     22 | fun tracing f = if !trace then Output.tracing (f ()) else ();
 | 
|  |     23 | 
 | 
| 19968 |     24 | 
 | 
|  |     25 | (* theory data setup *)
 | 
|  |     26 | 
 | 
| 20920 |     27 | structure NBE_Rewrite = TheoryDataFun
 | 
|  |     28 | (struct
 | 
|  |     29 |   val name = "Pure/nbe";
 | 
|  |     30 |   type T = thm list * thm list
 | 
|  |     31 | 
 | 
|  |     32 |   val empty = ([],[])
 | 
|  |     33 |   val copy = I;
 | 
|  |     34 |   val extend = I;
 | 
|  |     35 | 
 | 
|  |     36 |   fun merge _ ((pres1,posts1), (pres2,posts2)) =
 | 
|  |     37 |     (Library.merge eq_thm (pres1,pres2), Library.merge eq_thm (posts1,posts2))
 | 
|  |     38 | 
 | 
|  |     39 |   fun print _ _ = ()
 | 
|  |     40 | end);
 | 
|  |     41 | 
 | 
|  |     42 | val _ = Context.add_setup NBE_Rewrite.init;
 | 
|  |     43 | 
 | 
|  |     44 | fun consts_of_pres thy = 
 | 
|  |     45 |   let val pres = fst(NBE_Rewrite.get thy);
 | 
|  |     46 |       val rhss = map (snd o Logic.dest_equals o prop_of) pres;
 | 
|  |     47 |   in (fold o fold_aterms)
 | 
|  |     48 |         (fn Const c => insert (op =) (CodegenConsts.norm_of_typ thy c) | _ => I)
 | 
|  |     49 |         rhss []
 | 
|  |     50 |   end
 | 
|  |     51 | 
 | 
|  |     52 | 
 | 
|  |     53 | local
 | 
|  |     54 | 
 | 
|  |     55 | fun attr_pre (thy,thm) =
 | 
|  |     56 |  ((Context.map_theory o NBE_Rewrite.map o apfst) (insert eq_thm thm) thy, thm)
 | 
|  |     57 | fun attr_post (thy,thm) = 
 | 
|  |     58 |  ((Context.map_theory o NBE_Rewrite.map o apsnd) (insert eq_thm thm) thy, thm)
 | 
|  |     59 | 
 | 
|  |     60 | in
 | 
|  |     61 | val _ = Context.add_setup
 | 
|  |     62 |   (Attrib.add_attributes
 | 
|  |     63 |      [("normal_pre", Attrib.no_args attr_pre, "declare pre-theorems for normalization"),
 | 
|  |     64 |       ("normal_post", Attrib.no_args attr_post, "declare posy-theorems for normalization")]);
 | 
|  |     65 | end;
 | 
|  |     66 | 
 | 
|  |     67 | fun apply_pres thy =
 | 
|  |     68 |   let val pres = fst(NBE_Rewrite.get thy)
 | 
|  |     69 |   in map (CodegenData.rewrite_func pres) end
 | 
|  |     70 | 
 | 
|  |     71 | fun apply_posts thy =
 | 
|  |     72 |   let val posts = snd(NBE_Rewrite.get thy)
 | 
|  |     73 |   in Tactic.rewrite false posts end
 | 
|  |     74 | 
 | 
|  |     75 | 
 | 
| 20846 |     76 | structure NBE_Data = CodeDataFun
 | 
| 19147 |     77 | (struct
 | 
| 19962 |     78 |   val name = "Pure/NBE"
 | 
|  |     79 |   type T = NBE_Eval.Univ Symtab.table
 | 
|  |     80 |   val empty = Symtab.empty
 | 
|  |     81 |   fun merge _ = Symtab.merge (K true)
 | 
| 20937 |     82 |   fun purge _ _ _ = Symtab.empty
 | 
| 19147 |     83 | end);
 | 
|  |     84 | 
 | 
| 19968 |     85 | val _ = Context.add_setup NBE_Data.init;
 | 
| 19795 |     86 | 
 | 
|  |     87 | 
 | 
| 19968 |     88 | (* sandbox communication *)
 | 
| 19147 |     89 | 
 | 
| 19177 |     90 | val tab : NBE_Eval.Univ Symtab.table ref = ref Symtab.empty;
 | 
|  |     91 | fun lookup s = (the o Symtab.lookup (!tab)) s;
 | 
|  |     92 | fun update sx = (tab := Symtab.update sx (!tab));
 | 
|  |     93 | 
 | 
| 19147 |     94 | 
 | 
| 20846 |     95 | (* norm by eval *)
 | 
|  |     96 | 
 | 
|  |     97 | local
 | 
|  |     98 | 
 | 
|  |     99 | (* FIXME better turn this into a function
 | 
|  |    100 |     NBE_Eval.Univ Symtab.table -> NBE_Eval.Univ Symtab.table
 | 
|  |    101 |     with implicit side effect *)
 | 
|  |    102 | fun use_code NONE = ()
 | 
|  |    103 |   | use_code (SOME s) =
 | 
|  |    104 |       (tracing (fn () => "\n---generated code:\n" ^ s);
 | 
|  |    105 |        use_text (Output.tracing o enclose "\n---compiler echo:\n" "\n---\n",
 | 
|  |    106 |             Output.tracing o enclose "\n--- compiler echo (with error!):\n" "\n---\n")
 | 
|  |    107 |         (!trace) s);
 | 
|  |    108 | 
 | 
|  |    109 | fun generate thy funs =
 | 
|  |    110 |   let
 | 
|  |    111 |     val _ = tab := NBE_Data.get thy;;
 | 
|  |    112 |     val _ = Library.seq (use_code o NBE_Codegen.generate thy
 | 
|  |    113 |       (fn s => Symtab.defined (!tab) s)) funs;
 | 
|  |    114 |   in NBE_Data.change thy (K (!tab)) end;
 | 
|  |    115 | 
 | 
|  |    116 | fun compile_term thy t =
 | 
|  |    117 |   let
 | 
|  |    118 |     (*FIXME: proper interfaces in codegen_*)
 | 
|  |    119 |     val (consts, cs) = CodegenConsts.consts_of thy t;
 | 
|  |    120 |     val funcgr = CodegenFuncgr.mk_funcgr thy consts cs;
 | 
|  |    121 |     (*FIXME: proper interfaces in codegen_*)
 | 
|  |    122 |     fun const_typ (c, ty) =
 | 
| 19795 |    123 |       let
 | 
| 20846 |    124 |         val const = CodegenConsts.norm_of_typ thy (c, ty);
 | 
|  |    125 |       in case CodegenFuncgr.get_funcs funcgr const
 | 
|  |    126 |        of (thm :: _) => CodegenData.typ_func thy thm
 | 
|  |    127 |         | [] => Sign.the_const_type thy c
 | 
|  |    128 |       end;
 | 
|  |    129 |     val (_, ct) = CodegenData.preprocess_cterm thy const_typ (Thm.cterm_of thy t)
 | 
|  |    130 |     val t' = Thm.term_of ct;
 | 
|  |    131 |     val (consts, cs) = CodegenConsts.consts_of thy t';
 | 
| 20920 |    132 |     val pre_consts = consts_of_pres thy;
 | 
|  |    133 |     val consts' = pre_consts @ consts;
 | 
|  |    134 |     val funcgr = CodegenFuncgr.mk_funcgr thy consts' cs;
 | 
| 20846 |    135 |     val nbe_tab = NBE_Data.get thy;
 | 
|  |    136 |     val all_consts =
 | 
| 20920 |    137 |       (pre_consts :: CodegenFuncgr.all_deps_of funcgr consts')
 | 
| 20846 |    138 |       |> (map o filter_out) (Symtab.defined nbe_tab o CodegenNames.const thy)
 | 
|  |    139 |       |> filter_out null;
 | 
|  |    140 |     val funs = (map o map)
 | 
| 20920 |    141 |       (fn c => (CodegenNames.const thy c, apply_pres thy (CodegenFuncgr.get_funcs funcgr c))) all_consts;
 | 
| 20846 |    142 |     val _ = tracing (fn () => "new definitions: " ^ (commas o maps (map fst)) funs);
 | 
|  |    143 |     val _ = generate thy funs;
 | 
| 20856 |    144 |     val nt = NBE_Eval.eval thy (!tab) t';
 | 
| 20846 |    145 |   in nt end;
 | 
|  |    146 | 
 | 
|  |    147 | fun subst_Frees [] = I
 | 
|  |    148 |   | subst_Frees inst =
 | 
|  |    149 |       Term.map_aterms (fn (t as Free(s, _)) => the_default t (AList.lookup (op =) inst s)
 | 
|  |    150 |                   | t => t);
 | 
| 19795 |    151 | 
 | 
|  |    152 | fun var_tab t = (Term.add_frees t [], Term.add_vars t []);
 | 
|  |    153 | 
 | 
| 19968 |    154 | fun anno_vars (Ftab, Vtab) =
 | 
|  |    155 |   subst_Vars  (map (fn (ixn, T) => (ixn, Var(ixn,T))) Vtab) o
 | 
|  |    156 |   subst_Frees (map (fn (s, T) =>   (s,   Free(s,T)))  Ftab)
 | 
|  |    157 | 
 | 
| 20846 |    158 | in
 | 
| 19968 |    159 | 
 | 
| 20846 |    160 | fun norm_term thy t =
 | 
|  |    161 |   let
 | 
|  |    162 |     val _ = tracing (fn () => "Input:\n" ^ Display.raw_string_of_term t);
 | 
|  |    163 |     val nt = compile_term thy t;
 | 
|  |    164 |     val vtab = var_tab t;
 | 
|  |    165 |     val ty = type_of t;
 | 
|  |    166 |     fun constrain ty t = Sign.infer_types (Sign.pp thy) thy (Sign.consts_of thy)
 | 
|  |    167 |         (K NONE) (K NONE) Name.context false ([t], ty) |> fst;
 | 
|  |    168 |     val _ = tracing (fn () => "Normalized:\n" ^ NBE_Eval.string_of_nterm nt);
 | 
| 20920 |    169 |     val t1 = NBE_Codegen.nterm_to_term thy nt;
 | 
|  |    170 |     val _ = tracing (fn () =>"Converted back:\n" ^ Display.raw_string_of_term t1);
 | 
|  |    171 |     val t2 = anno_vars vtab t1;
 | 
|  |    172 |     val _ = tracing (fn () =>"Vars typed:\n" ^ Display.raw_string_of_term t2);
 | 
|  |    173 |     val t3 = constrain ty t2;
 | 
|  |    174 |     val _ = if null (Term.term_tvars t3) then () else
 | 
| 20846 |    175 |       error ("Illegal schematic type variables in normalized term: "
 | 
| 20920 |    176 |         ^ setmp show_types true (Sign.string_of_term thy) t3);
 | 
|  |    177 |     val eq = apply_posts thy (Thm.cterm_of thy t3);
 | 
|  |    178 |     val t4 = snd(Logic.dest_equals(prop_of eq))
 | 
|  |    179 |   in t4 end;
 | 
| 20846 |    180 | 
 | 
|  |    181 | fun norm_print_term ctxt modes t =
 | 
|  |    182 |   let
 | 
|  |    183 |     val thy = ProofContext.theory_of ctxt;
 | 
|  |    184 |     val t' = norm_term thy t;
 | 
|  |    185 |     val ty = Term.type_of t';
 | 
|  |    186 |     val p = Library.setmp print_mode (modes @ ! print_mode) (fn () =>
 | 
|  |    187 |       Pretty.block [Pretty.quote (ProofContext.pretty_term ctxt t'), Pretty.fbrk,
 | 
|  |    188 |         Pretty.str "::", Pretty.brk 1, Pretty.quote (ProofContext.pretty_typ ctxt ty)]) ();
 | 
|  |    189 |   in Pretty.writeln p end;
 | 
|  |    190 | 
 | 
|  |    191 | fun norm_print_term_e (modes, raw_t) state =
 | 
|  |    192 |   let
 | 
| 21002 |    193 |     val ctxt = Context.proof_of (Toplevel.context_of state);
 | 
| 20846 |    194 |   in norm_print_term ctxt modes (ProofContext.read_term ctxt raw_t) end;
 | 
|  |    195 | 
 | 
|  |    196 | end; (*local*)
 | 
| 19968 |    197 | 
 | 
|  |    198 | 
 | 
| 20846 |    199 | (* normalization oracle *)
 | 
| 19962 |    200 | 
 | 
| 20602 |    201 | exception Normalization of term;
 | 
|  |    202 | 
 | 
|  |    203 | fun normalization_oracle (thy, Normalization t) =
 | 
|  |    204 |   Logic.mk_equals (t, norm_term thy t);
 | 
|  |    205 | 
 | 
|  |    206 | fun normalization_conv ct =
 | 
|  |    207 |   let val {sign, t, ...} = rep_cterm ct
 | 
| 20677 |    208 |   in Thm.invoke_oracle_i sign "Pure.normalization" (sign, Normalization t) end;
 | 
| 20602 |    209 | 
 | 
|  |    210 | val _ = Context.add_setup
 | 
| 20677 |    211 |   (Theory.add_oracle ("normalization", normalization_oracle));
 | 
| 19177 |    212 | 
 | 
| 20846 |    213 | 
 | 
| 19968 |    214 | (* Isar setup *)
 | 
|  |    215 | 
 | 
|  |    216 | local structure P = OuterParse and K = OuterKeyword in
 | 
| 19147 |    217 | 
 | 
| 20846 |    218 | val opt_modes = Scan.optional (P.$$$ "(" |-- P.!!! (Scan.repeat1 P.xname --| P.$$$ ")")) [];
 | 
|  |    219 | 
 | 
| 19147 |    220 | val nbeP =
 | 
| 20846 |    221 |   OuterSyntax.improper_command "normal_form" "normalize term by evaluation" K.diag
 | 
|  |    222 |     (opt_modes -- P.typ >> (Toplevel.keep o norm_print_term_e));
 | 
| 19968 |    223 | 
 | 
|  |    224 | end;
 | 
| 19147 |    225 | 
 | 
|  |    226 | val _ = OuterSyntax.add_parsers [nbeP];
 | 
|  |    227 | 
 | 
| 19177 |    228 | end;
 |