src/HOL/Tools/Quickcheck/narrowing_generators.ML
changeset 43047 26774ccb1c74
parent 42616 92715b528e78
child 43079 4022892a2f28
equal deleted inserted replaced
43046:2a1b01680505 43047:26774ccb1c74
    17 struct
    17 struct
    18 
    18 
    19 (* configurations *)
    19 (* configurations *)
    20 
    20 
    21 val finite_functions = Attrib.setup_config_bool @{binding quickcheck_finite_functions} (K true)
    21 val finite_functions = Attrib.setup_config_bool @{binding quickcheck_finite_functions} (K true)
    22 
    22 val overlord = Attrib.setup_config_bool @{binding quickcheck_narrowing_overlord} (K false)
    23 (* narrowing specific names and types *)
    23 
       
    24 (* partial_term_of instances *)
       
    25 
       
    26 fun mk_partial_term_of (x, T) =
       
    27   Const (@{const_name Quickcheck_Narrowing.partial_term_of_class.partial_term_of},
       
    28     Term.itselfT T --> @{typ narrowing_term} --> @{typ Code_Evaluation.term})
       
    29       $ Const ("TYPE", Term.itselfT T) $ x
       
    30 
       
    31 (** formal definition **)
       
    32 
       
    33 fun add_partial_term_of tyco raw_vs thy =
       
    34   let
       
    35     val vs = map (fn (v, _) => (v, @{sort typerep})) raw_vs;
       
    36     val ty = Type (tyco, map TFree vs);
       
    37     val lhs = Const (@{const_name partial_term_of},
       
    38         Term.itselfT ty --> @{typ narrowing_term} --> @{typ Code_Evaluation.term})
       
    39       $ Free ("x", Term.itselfT ty) $ Free ("t", @{typ narrowing_term});
       
    40     val rhs = @{term "undefined :: Code_Evaluation.term"};
       
    41     val eq = HOLogic.mk_Trueprop (HOLogic.mk_eq (lhs, rhs));
       
    42     fun triv_name_of t = (fst o dest_Free o fst o strip_comb o fst
       
    43       o HOLogic.dest_eq o HOLogic.dest_Trueprop) t ^ "_triv";
       
    44   in
       
    45     thy
       
    46     |> Class.instantiation ([tyco], vs, @{sort partial_term_of})
       
    47     |> `(fn lthy => Syntax.check_term lthy eq)
       
    48     |-> (fn eq => Specification.definition (NONE, ((Binding.name (triv_name_of eq), []), eq)))
       
    49     |> snd
       
    50     |> Class.prove_instantiation_exit (K (Class.intro_classes_tac []))
       
    51   end;
       
    52 
       
    53 fun ensure_partial_term_of (tyco, (raw_vs, _)) thy =
       
    54   let
       
    55     val need_inst = not (can (Sorts.mg_domain (Sign.classes_of thy) tyco) @{sort partial_term_of})
       
    56       andalso can (Sorts.mg_domain (Sign.classes_of thy) tyco) @{sort typerep};
       
    57   in if need_inst then add_partial_term_of tyco raw_vs thy else thy end;
       
    58 
       
    59 
       
    60 (** code equations for datatypes **)
       
    61 
       
    62 fun mk_partial_term_of_eq thy ty (i, (c, (_, tys))) =
       
    63   let
       
    64     val frees = map Free (Name.names Name.context "a" (map (K @{typ narrowing_term}) tys))
       
    65     val narrowing_term = @{term "Quickcheck_Narrowing.Ctr"} $ HOLogic.mk_number @{typ code_int} i
       
    66       $ (HOLogic.mk_list @{typ narrowing_term} frees)
       
    67     val rhs = fold (fn u => fn t => @{term "Code_Evaluation.App"} $ t $ u)
       
    68         (map mk_partial_term_of (frees ~~ tys))
       
    69         (@{term "Code_Evaluation.Const"} $ HOLogic.mk_literal c $ HOLogic.mk_typerep (tys ---> ty))
       
    70     val insts =
       
    71       map (SOME o Thm.cterm_of thy o map_types Logic.unvarifyT_global o Logic.varify_global)
       
    72         [Free ("ty", Term.itselfT ty), narrowing_term, rhs]
       
    73     val cty = Thm.ctyp_of thy ty;
       
    74   in
       
    75     @{thm partial_term_of_anything}
       
    76     |> Drule.instantiate' [SOME cty] insts
       
    77     |> Thm.varifyT_global
       
    78   end
       
    79 
       
    80 fun add_partial_term_of_code tyco raw_vs raw_cs thy =
       
    81   let
       
    82     val algebra = Sign.classes_of thy;
       
    83     val vs = map (fn (v, sort) =>
       
    84       (v, curry (Sorts.inter_sort algebra) @{sort typerep} sort)) raw_vs;
       
    85     val ty = Type (tyco, map TFree vs);
       
    86     val cs = (map o apsnd o apsnd o map o map_atyps)
       
    87       (fn TFree (v, _) => TFree (v, (the o AList.lookup (op =) vs) v)) raw_cs;
       
    88     val const = AxClass.param_of_inst thy (@{const_name partial_term_of}, tyco);
       
    89     val eqs = map_index (mk_partial_term_of_eq thy ty) cs;
       
    90  in
       
    91     thy
       
    92     |> Code.del_eqns const
       
    93     |> fold Code.add_eqn eqs
       
    94   end;
       
    95 
       
    96 fun ensure_partial_term_of_code (tyco, (raw_vs, cs)) thy =
       
    97   let
       
    98     val has_inst = can (Sorts.mg_domain (Sign.classes_of thy) tyco) @{sort partial_term_of};
       
    99   in if has_inst then add_partial_term_of_code tyco raw_vs cs thy else thy end;
       
   100 
       
   101 
       
   102 (* narrowing generators *)
       
   103 
       
   104 (** narrowing specific names and types **)
    24 
   105 
    25 exception FUNCTION_TYPE;
   106 exception FUNCTION_TYPE;
    26 
   107 
    27 val narrowingN = "narrowing";
   108 val narrowingN = "narrowing";
    28 
   109 
    46     val T = fastype_of t
   127     val T = fastype_of t
    47   in
   128   in
    48     Const (@{const_name Quickcheck_Narrowing.sum}, T --> T --> T) $ t $ u
   129     Const (@{const_name Quickcheck_Narrowing.sum}, T --> T --> T) $ t $ u
    49   end
   130   end
    50 
   131 
    51 (* creating narrowing instances *)
   132 (** deriving narrowing instances **)
    52 
   133 
    53 fun mk_equations descr vs tycos narrowings (Ts, Us) =
   134 fun mk_equations descr vs tycos narrowings (Ts, Us) =
    54   let
   135   let
    55     fun mk_call T =
   136     fun mk_call T =
    56       (T, Const (@{const_name "Quickcheck_Narrowing.narrowing_class.narrowing"}, narrowingT T))
   137       (T, Const (@{const_name "Quickcheck_Narrowing.narrowing_class.narrowing"}, narrowingT T))
    93 
   174 
    94 (* testing framework *)
   175 (* testing framework *)
    95 
   176 
    96 val target = "Haskell"
   177 val target = "Haskell"
    97 
   178 
    98 (* invocation of Haskell interpreter *)
   179 (** invocation of Haskell interpreter **)
    99 
   180 
   100 val narrowing_engine = File.read (Path.explode "~~/src/HOL/Tools/Quickcheck/Narrowing_Engine.hs")
   181 val narrowing_engine = File.read (Path.explode "~~/src/HOL/Tools/Quickcheck/Narrowing_Engine.hs")
   101 
   182 
   102 fun exec verbose code =
   183 fun exec verbose code =
   103   ML_Context.exec (fn () => Secure.use_text ML_Env.local_context (0, "generated code") verbose code)
   184   ML_Context.exec (fn () => Secure.use_text ML_Env.local_context (0, "generated code") verbose code)
   104 
   185 
       
   186 fun with_tmp_dir name f =
       
   187   let
       
   188     val path = Path.append (Path.explode "~/.isabelle") (Path.basic (name ^ serial_string ()))
       
   189     val _ = Isabelle_System.mkdirs path;
       
   190   in Exn.release (Exn.capture f path) end;
       
   191   
   105 fun value ctxt (get, put, put_ml) (code, value) size =
   192 fun value ctxt (get, put, put_ml) (code, value) size =
   106   let
   193   let
   107     val tmp_prefix = "Quickcheck_Narrowing"
   194     val tmp_prefix = "Quickcheck_Narrowing"
       
   195     val with_tmp_dir = if Config.get ctxt overlord 
       
   196       then Isabelle_System.with_tmp_dir else Quickcheck_Narrowing.with_tmp_dir 
   108     fun run in_path = 
   197     fun run in_path = 
   109       let
   198       let
   110         val code_file = Path.append in_path (Path.basic "Code.hs")
   199         val code_file = Path.append in_path (Path.basic "Code.hs")
   111         val narrowing_engine_file = Path.append in_path (Path.basic "Narrowing_Engine.hs")
   200         val narrowing_engine_file = Path.append in_path (Path.basic "Narrowing_Engine.hs")
   112         val main_file = Path.append in_path (Path.basic "Main.hs")
   201         val main_file = Path.append in_path (Path.basic "Main.hs")
   125           (space_implode " " (map File.shell_path [code_file, narrowing_engine_file, main_file])) ^
   214           (space_implode " " (map File.shell_path [code_file, narrowing_engine_file, main_file])) ^
   126           " -o " ^ executable ^ "; ) && " ^ executable
   215           " -o " ^ executable ^ "; ) && " ^ executable
   127       in
   216       in
   128         bash_output cmd
   217         bash_output cmd
   129       end
   218       end
   130     val result = Isabelle_System.with_tmp_dir tmp_prefix run
   219     val result = with_tmp_dir tmp_prefix run
   131     val output_value = the_default "NONE"
   220     val output_value = the_default "NONE"
   132       (try (snd o split_last o filter_out (fn s => s = "") o split_lines o fst) result)
   221       (try (snd o split_last o filter_out (fn s => s = "") o split_lines o fst) result)
   133       |> translate_string (fn s => if s = "\\" then "\\\\" else s)
   222       |> translate_string (fn s => if s = "\\" then "\\\\" else s)
   134     val ml_code = "\nval _ = Context.set_thread_data (SOME (Context.map_proof (" ^ put_ml
   223     val ml_code = "\nval _ = Context.set_thread_data (SOME (Context.map_proof (" ^ put_ml
   135       ^ " (fn () => " ^ output_value ^ ")) (ML_Context.the_generic_context ())))";
   224       ^ " (fn () => " ^ output_value ^ ")) (ML_Context.the_generic_context ())))";
   150   let
   239   let
   151     fun evaluator naming program ((_, vs_ty), t) deps =
   240     fun evaluator naming program ((_, vs_ty), t) deps =
   152       evaluation cookie thy (Code_Target.evaluator thy target naming program deps) (vs_ty, t) args size;
   241       evaluation cookie thy (Code_Target.evaluator thy target naming program deps) (vs_ty, t) args size;
   153   in Exn.release (Code_Thingol.dynamic_value thy (Exn.map_result o postproc) evaluator t) end;
   242   in Exn.release (Code_Thingol.dynamic_value thy (Exn.map_result o postproc) evaluator t) end;
   154 
   243 
   155 (* counterexample generator *)
   244 (** counterexample generator **)
   156   
   245   
   157 structure Counterexample = Proof_Data
   246 structure Counterexample = Proof_Data
   158 (
   247 (
   159   type T = unit -> term list option
   248   type T = unit -> term list option
   160   fun init _ () = error "Counterexample"
   249   fun init _ () = error "Counterexample"
   201       thy (Option.map o map) (ensure_testable t'') [] size
   290       thy (Option.map o map) (ensure_testable t'') [] size
   202   in
   291   in
   203     (result, NONE)
   292     (result, NONE)
   204   end;
   293   end;
   205 
   294 
       
   295 (* setup *)
   206 
   296 
   207 val setup =
   297 val setup =
   208   Datatype.interpretation (Quickcheck_Common.ensure_sort_datatype
   298   Code.datatype_interpretation ensure_partial_term_of
       
   299   #> Code.datatype_interpretation ensure_partial_term_of_code
       
   300   #> Datatype.interpretation (Quickcheck_Common.ensure_sort_datatype
   209     (((@{sort typerep}, @{sort term_of}), @{sort narrowing}), instantiate_narrowing_datatype))
   301     (((@{sort typerep}, @{sort term_of}), @{sort narrowing}), instantiate_narrowing_datatype))
   210   #> Context.theory_map
   302   #> Context.theory_map
   211     (Quickcheck.add_generator ("narrowing", compile_generator_expr))
   303     (Quickcheck.add_generator ("narrowing", compile_generator_expr))
   212     
   304     
   213 end;
   305 end;