quickcheck generators for abstract types; tuned
authorbulwahn
Tue, 20 Dec 2011 17:39:56 +0100
changeset 45925 cd4243c025bb
parent 45924 f03dd48829d8
child 45926 f4f22d87e364
quickcheck generators for abstract types; tuned
src/HOL/Quickcheck_Exhaustive.thy
src/HOL/Tools/Quickcheck/abstract_generators.ML
--- a/src/HOL/Quickcheck_Exhaustive.thy	Tue Dec 20 17:22:31 2011 +0100
+++ b/src/HOL/Quickcheck_Exhaustive.thy	Tue Dec 20 17:39:56 2011 +0100
@@ -4,7 +4,9 @@
 
 theory Quickcheck_Exhaustive
 imports Quickcheck
-uses ("Tools/Quickcheck/exhaustive_generators.ML")
+uses
+  ("Tools/Quickcheck/exhaustive_generators.ML")
+  ("Tools/Quickcheck/abstract_generators.ML")
 begin
 
 subsection {* basic operations for exhaustive generators *}
@@ -521,7 +523,7 @@
 where
   "pos_bound_cps_not n = (%c i. case n (%u. Value []) i of No_value => c () | Value _ => None | Unknown_value => None)"
 
-subsection {* Defining combinators for any first-order data type *}
+subsection {* Defining generators for any first-order data type *}
 
 axiomatization unknown :: 'a
 
@@ -533,6 +535,10 @@
 
 declare [[quickcheck_batch_tester = exhaustive]]
 
+subsection {* Defining generators for abstract types *}
+
+use "Tools/Quickcheck/abstract_generators.ML"
+
 hide_fact orelse_def
 no_notation orelse (infixr "orelse" 55)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HOL/Tools/Quickcheck/abstract_generators.ML	Tue Dec 20 17:39:56 2011 +0100
@@ -0,0 +1,64 @@
+(*  Title:      HOL/Tools/Quickcheck/abstract_generators.ML
+    Author:     Lukas Bulwahn, TU Muenchen
+
+Quickcheck generators for abstract types.
+*)
+
+signature ABSTRACT_GENERATORS =
+sig
+  val quickcheck_generator : string -> term list -> theory -> theory
+end;
+
+structure Abstract_Generators : ABSTRACT_GENERATORS =
+struct
+
+fun check_constrs ctxt tyco constrs =
+  let
+    fun check_type c =
+      case try (dest_Type o body_type o fastype_of) c of
+        NONE => error (Syntax.string_of_term ctxt c ^ " has mismatching result type.")
+      | SOME (tyco', vs) => if not (tyco' = tyco) then
+            error (Syntax.string_of_term ctxt c ^ " has mismatching result type. " ^
+              "Expected type constructor " ^ quote tyco ^ ", but found " ^ quote tyco' ^ ".")
+          else
+            case try (map dest_TFree) vs of
+              NONE => error (Syntax.string_of_term ctxt c ^ " has mismatching result type.")
+            | SOME _ => ()
+  in
+    map check_type constrs
+  end
+  
+fun gen_quickcheck_generator prep_tyco prep_term tyco_raw constrs_raw thy =
+  let
+    val ctxt = Proof_Context.init_global thy
+    val tyco = prep_tyco ctxt tyco_raw
+    val constrs = map (prep_term ctxt) constrs_raw
+    val _ = check_constrs ctxt tyco constrs 
+    val vs = map dest_TFree (snd (dest_Type (body_type (fastype_of (hd constrs)))))
+    val name = Long_Name.base_name tyco 
+    fun mk_dconstrs (Const (s, T)) =
+        (s, map (Datatype_Aux.dtyp_of_typ [(tyco, vs)]) (binder_types T))
+      | mk_dconstrs t = error (Syntax.string_of_term ctxt t ^
+          " is not a valid constructor for quickcheck_generator, which expects a constant.")
+    fun the_descr thy _ =
+      let
+        val descr = [(0, (tyco, map Datatype_Aux.DtTFree vs, map mk_dconstrs constrs))]
+      in
+        (descr, vs, [tyco], name, ([name], []), ([Type (tyco, map TFree vs)], []))
+      end
+  in
+    Quickcheck_Common.ensure_sort (((@{sort typerep}, @{sort term_of}), @{sort full_exhaustive}),
+        (the_descr, Exhaustive_Generators.instantiate_full_exhaustive_datatype))
+      Datatype_Aux.default_config [tyco] thy
+  end
+
+val quickcheck_generator = gen_quickcheck_generator (K I) (K I)
+  
+val quickcheck_generator_cmd = gen_quickcheck_generator
+  (fn ctxt => fst o dest_Type o Proof_Context.read_type_name_proper ctxt false) Syntax.read_term
+  
+val _ = Outer_Syntax.command "quickcheck_generator" "define quickcheck generators for abstract types"
+    Keyword.thy_decl (Parse.type_const -- (Args.$$$ "constructors" |-- Parse.$$$ ":" |-- Parse.list1 Parse.term)
+      >> (fn (tyco, constrs) => Toplevel.theory (quickcheck_generator_cmd tyco constrs)))
+
+end;
\ No newline at end of file