src/Pure/Isar/rule_cases.ML
changeset 18608 9cdcc2a5c8b3
parent 18581 6538fdcc98dc
child 18728 6790126ab5f6
equal deleted inserted replaced
18607:7b074c340aac 18608:9cdcc2a5c8b3
    18 end
    18 end
    19 
    19 
    20 signature RULE_CASES =
    20 signature RULE_CASES =
    21 sig
    21 sig
    22   include BASIC_RULE_CASES
    22   include BASIC_RULE_CASES
    23   type T
    23   datatype T = Case of
       
    24    {fixes: (string * typ) list,
       
    25     assumes: (string * term list) list,
       
    26     binds: (indexname * term option) list,
       
    27     cases: (string * T) list}
       
    28   val strip_params: term -> (string * typ) list
       
    29   val make_common: bool -> theory * term -> (string * string list) list -> cases
       
    30   val make_nested: bool -> term -> theory * term -> (string * string list) list -> cases
       
    31   val make_simple: bool -> theory * term -> string -> cases
       
    32   val apply: term list -> T -> T
    24   val consume: thm list -> thm list -> ('a * int) * thm ->
    33   val consume: thm list -> thm list -> ('a * int) * thm ->
    25     (('a * (int * thm list)) * thm) Seq.seq
    34     (('a * (int * thm list)) * thm) Seq.seq
    26   val add_consumes: int -> thm -> thm
    35   val add_consumes: int -> thm -> thm
    27   val consumes: int -> 'a attribute
    36   val consumes: int -> 'a attribute
    28   val consumes_default: int -> 'a attribute
    37   val consumes_default: int -> 'a attribute
    29   val name: string list -> thm -> thm
    38   val name: string list -> thm -> thm
    30   val case_names: string list -> 'a attribute
    39   val case_names: string list -> 'a attribute
    31   val case_conclusion: string * string list -> 'a attribute
    40   val case_conclusion: string * string list -> 'a attribute
    32   val save: thm -> thm -> thm
    41   val save: thm -> thm -> thm
    33   val get: thm -> (string * string list) list * int
    42   val get: thm -> (string * string list) list * int
    34   val strip_params: term -> (string * typ) list
       
    35   val make: bool -> term option -> theory * term -> (string * string list) list -> cases
       
    36   val simple: theory * term -> string -> cases
       
    37   val rename_params: string list list -> thm -> thm
    43   val rename_params: string list list -> thm -> thm
    38   val params: string list list -> 'a attribute
    44   val params: string list list -> 'a attribute
    39   val mutual_rule: thm list -> (int list * thm) option
    45   val mutual_rule: thm list -> (int list * thm) option
    40   val strict_mutual_rule: thm list -> int list * thm
    46   val strict_mutual_rule: thm list -> int list * thm
    41 end;
    47 end;
    42 
    48 
    43 structure RuleCases: RULE_CASES =
    49 structure RuleCases: RULE_CASES =
    44 struct
    50 struct
    45 
    51 
    46 (** tactics with cases **)
    52 (** cases **)
    47 
    53 
    48 type T =
    54 datatype T = Case of
    49  {fixes: (string * typ) list,
    55  {fixes: (string * typ) list,
    50   assumes: (string * term list) list,
    56   assumes: (string * term list) list,
    51   binds: (indexname * term option) list};
    57   binds: (indexname * term option) list,
       
    58   cases: (string * T) list};
    52 
    59 
    53 type cases = (string * T option) list;
    60 type cases = (string * T option) list;
       
    61 
       
    62 val case_conclN = "case";
       
    63 val case_hypsN = "hyps";
       
    64 val case_premsN = "prems";
       
    65 
       
    66 val strip_params = map (apfst (perhaps (try Syntax.dest_skolem))) o Logic.strip_params;
       
    67 
       
    68 local
       
    69 
       
    70 fun abs xs t = Term.list_abs (xs, t);
       
    71 fun app us t = Term.betapplys (t, us);
       
    72 
       
    73 fun dest_binops cs tm =
       
    74   let
       
    75     val n = length cs;
       
    76     fun dest 0 _ = []
       
    77       | dest 1 t = [t]
       
    78       | dest k (_ $ t $ u) = t :: dest (k - 1) u
       
    79       | dest _ _ = raise TERM ("Expected " ^ string_of_int n ^ " binop arguments", [tm]);
       
    80   in cs ~~ dest n tm end;
       
    81 
       
    82 fun extract_fixes NONE prop = (strip_params prop, [])
       
    83   | extract_fixes (SOME outline) prop =
       
    84       splitAt (length (Logic.strip_params outline), strip_params prop);
       
    85 
       
    86 fun extract_assumes _ NONE prop = ([("", Logic.strip_assums_hyp prop)], [])
       
    87   | extract_assumes qual (SOME outline) prop =
       
    88       let val (hyps, prems) =
       
    89         splitAt (length (Logic.strip_assums_hyp outline), Logic.strip_assums_hyp prop)
       
    90       in ([(qual case_hypsN, hyps)], [(qual case_premsN, prems)]) end;
       
    91 
       
    92 fun extract_case is_open thy (case_outline, raw_prop) name concls =
       
    93   let
       
    94     val rename = if is_open then I else (apfst Syntax.internal);
       
    95 
       
    96     val props = Logic.dest_conjunctions (Drule.norm_hhf thy raw_prop);
       
    97     val len = length props;
       
    98     val nested = is_some case_outline andalso len > 1;
       
    99 
       
   100     fun extract prop =
       
   101       let
       
   102         val (fixes1, fixes2) = extract_fixes case_outline prop
       
   103           |> apfst (map rename);
       
   104         val abs_fixes = abs (fixes1 @ fixes2);
       
   105         fun abs_fixes1 t =
       
   106           if not nested then abs_fixes t
       
   107           else abs fixes1 (app (map (Term.dummy_pattern o #2) fixes2) (abs fixes2 t));
       
   108 
       
   109         val (assumes1, assumes2) = extract_assumes (NameSpace.qualified name) case_outline prop
       
   110           |> pairself (map (apsnd (List.concat o map Logic.dest_conjunctions)));
       
   111 
       
   112         val concl = ObjectLogic.drop_judgment thy (Logic.strip_assums_concl prop);
       
   113         val binds =
       
   114           (case_conclN, concl) :: dest_binops concls concl
       
   115           |> map (fn (x, t) => ((x, 0), SOME (abs_fixes t)));
       
   116       in
       
   117        ((fixes1, map (apsnd (map abs_fixes1)) assumes1),
       
   118         ((fixes2, map (apsnd (map abs_fixes)) assumes2), binds))
       
   119       end;
       
   120 
       
   121     val cases = map extract props;
       
   122 
       
   123     fun common_case ((fixes1, assumes1), ((fixes2, assumes2), binds)) =
       
   124       Case {fixes = fixes1 @ fixes2, assumes = assumes1 @ assumes2, binds = binds, cases = []};
       
   125     fun inner_case (_, ((fixes2, assumes2), binds)) =
       
   126       Case {fixes = fixes2, assumes = assumes2, binds = binds, cases = []};
       
   127     fun nested_case ((fixes1, assumes1), _) =
       
   128       Case {fixes = fixes1, assumes = assumes1, binds = [],
       
   129         cases = map string_of_int (1 upto len) ~~ map inner_case cases};
       
   130   in
       
   131     if len = 0 then NONE
       
   132     else if len = 1 then SOME (common_case (hd cases))
       
   133     else if is_none case_outline orelse length (gen_distinct (op =) (map fst cases)) > 1 then NONE
       
   134     else SOME (nested_case (hd cases))
       
   135   end;
       
   136 
       
   137 fun make is_open rule_struct (thy, prop) cases =
       
   138   let
       
   139     val n = length cases;
       
   140     val nprems = Logic.count_prems (prop, 0);
       
   141     fun add_case (name, concls) (cs, i) =
       
   142       ((case try (fn () =>
       
   143           (Option.map (curry Logic.nth_prem i) rule_struct, Logic.nth_prem (i, prop))) () of
       
   144         NONE => (name, NONE)
       
   145       | SOME p => (name, extract_case is_open thy p name concls)) :: cs, i - 1);
       
   146   in fold_rev add_case (Library.drop (n - nprems, cases)) ([], n) |> #1 end;
       
   147 
       
   148 in
       
   149 
       
   150 fun make_common is_open = make is_open NONE;
       
   151 fun make_nested is_open rule_struct = make is_open (SOME rule_struct);
       
   152 fun make_simple is_open (thy, prop) name = [(name, extract_case is_open thy (NONE, prop) "" [])];
       
   153 
       
   154 fun apply args =
       
   155   let
       
   156     fun appl (Case {fixes, assumes, binds, cases}) =
       
   157       let
       
   158         val assumes' = map (apsnd (map (app args))) assumes;
       
   159         val binds' = map (apsnd (Option.map (app args))) binds;
       
   160         val cases' = map (apsnd appl) cases;
       
   161       in Case {fixes = fixes, assumes = assumes', binds = binds', cases = cases'} end;
       
   162   in appl end;
       
   163 
       
   164 end;
       
   165 
       
   166 
       
   167 
       
   168 (** tactics with cases **)
       
   169 
    54 type cases_tactic = thm -> (cases * thm) Seq.seq;
   170 type cases_tactic = thm -> (cases * thm) Seq.seq;
    55 
   171 
    56 fun CASES cases tac st = Seq.map (pair cases) (tac st);
   172 fun CASES cases tac st = Seq.map (pair cases) (tac st);
    57 fun NO_CASES tac = CASES [] tac;
   173 fun NO_CASES tac = CASES [] tac;
    58 
   174 
   177     val cases =
   293     val cases =
   178       (case lookup_case_names th of
   294       (case lookup_case_names th of
   179         NONE => map (rpair [] o Library.string_of_int) (1 upto (Thm.nprems_of th - n))
   295         NONE => map (rpair [] o Library.string_of_int) (1 upto (Thm.nprems_of th - n))
   180       | SOME names => map (fn name => (name, get_case_concls th name)) names);
   296       | SOME names => map (fn name => (name, get_case_concls th name)) names);
   181   in (cases, n) end;
   297   in (cases, n) end;
   182 
       
   183 
       
   184 (* extract cases *)
       
   185 
       
   186 val case_conclN = "case";
       
   187 val case_hypsN = "hyps";
       
   188 val case_premsN = "prems";
       
   189 
       
   190 val strip_params = map (apfst (perhaps (try Syntax.dest_skolem))) o Logic.strip_params;
       
   191 
       
   192 local
       
   193 
       
   194 fun dest_binops cs tm =
       
   195   let
       
   196     val n = length cs;
       
   197     fun dest 0 _ = []
       
   198       | dest 1 t = [t]
       
   199       | dest k (_ $ t $ u) = t :: dest (k - 1) u
       
   200       | dest _ _ = raise TERM ("Expected " ^ string_of_int n ^ " binop arguments", [tm]);
       
   201   in cs ~~ dest n tm end;
       
   202 
       
   203 fun extract_cases is_open thy (split, raw_prop) name concls =
       
   204   let
       
   205     fun extract prop idx =
       
   206       let
       
   207         val xs = strip_params prop;
       
   208         val rename = if is_open then I else map (apfst Syntax.internal);
       
   209         val fixes =
       
   210           (case split of
       
   211             NONE => rename xs
       
   212           | SOME t =>
       
   213               let val (us, vs) = splitAt (length (Logic.strip_params t), xs)
       
   214               in rename us @ vs end);
       
   215         fun abs_fixes t = Term.list_abs (fixes, t);
       
   216         val dest_conjuncts = map abs_fixes o List.concat o map Logic.dest_conjunctions;
       
   217 
       
   218         val asms = Logic.strip_assums_hyp prop;
       
   219         val assumes =
       
   220           (case split of
       
   221             NONE => [("", dest_conjuncts asms)]
       
   222           | SOME t =>
       
   223               let val (hyps, prems) = splitAt (length (Logic.strip_assums_hyp t), asms) in
       
   224                [(case_hypsN, dest_conjuncts hyps),
       
   225                 (case_premsN, dest_conjuncts prems)]
       
   226               end);
       
   227 
       
   228         val concl = ObjectLogic.drop_judgment thy (Logic.strip_assums_concl prop);
       
   229         val binds = (case_conclN, concl) :: dest_binops concls concl
       
   230           |> map (fn (x, t) => ((x, 0), SOME (abs_fixes t)));
       
   231       in (name ^ idx, SOME {fixes = fixes, assumes = assumes, binds = binds}) end;
       
   232   in
       
   233     (case Logic.dest_conjunctions (Drule.norm_hhf thy raw_prop) of
       
   234       [prop] => [extract prop ""]
       
   235     | props => map2 extract props (map string_of_int (1 upto length props)))
       
   236   end;
       
   237 
       
   238 in
       
   239 
       
   240 fun make is_open split (thy, prop) cases =
       
   241   let
       
   242     val n = length cases;
       
   243     val nprems = Logic.count_prems (prop, 0);
       
   244     fun add_case (name, concls) (cs, i) =
       
   245       ((case try (fn () =>
       
   246           (Option.map (curry Logic.nth_prem i) split, Logic.nth_prem (i, prop))) () of
       
   247         NONE => [(name, NONE)]
       
   248       | SOME sp => extract_cases is_open thy sp name concls) @ cs, i - 1);
       
   249   in fold_rev add_case (Library.drop (n - nprems, cases)) ([], n) |> #1 end;
       
   250 
       
   251 fun simple (thy, prop) name =
       
   252   extract_cases true thy (NONE, prop) name [];
       
   253 
       
   254 end;
       
   255 
   298 
   256 
   299 
   257 (* params *)
   300 (* params *)
   258 
   301 
   259 fun rename_params xss th =
   302 fun rename_params xss th =