src/HOL/Library/simps_case_conv.ML
author wenzelm
Wed, 13 Apr 2016 18:01:05 +0200
changeset 62969 9f394a16c557
parent 61813 b84688dd7f6b
child 63344 c9910404cc8a
permissions -rw-r--r--
eliminated "xname" and variants;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
     1
(*  Title:      HOL/Library/simps_case_conv.ML
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
     2
    Author:     Lars Noschinski, TU Muenchen
53433
3b356b7f7cad more standard header;
wenzelm
parents: 53429
diff changeset
     3
    Author:     Gerwin Klein, NICTA
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
     4
53433
3b356b7f7cad more standard header;
wenzelm
parents: 53429
diff changeset
     5
Convert function specifications between the representation as a list
3b356b7f7cad more standard header;
wenzelm
parents: 53429
diff changeset
     6
of equations (with patterns on the lhs) and a single equation (with a
3b356b7f7cad more standard header;
wenzelm
parents: 53429
diff changeset
     7
nested case expression on the rhs).
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
     8
*)
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
     9
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    10
signature SIMPS_CASE_CONV =
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    11
sig
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    12
  val to_case: Proof.context -> thm list -> thm
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    13
  val gen_to_simps: Proof.context -> thm list -> thm -> thm list
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    14
  val to_simps: Proof.context -> thm -> thm list
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    15
end
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    16
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    17
structure Simps_Case_Conv: SIMPS_CASE_CONV =
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    18
struct
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    19
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    20
(* Collects all type constructors in a type *)
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    21
fun collect_Tcons (Type (name,Ts)) = name :: maps collect_Tcons Ts
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    22
  | collect_Tcons (TFree _) = []
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    23
  | collect_Tcons (TVar _) = []
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    24
60702
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    25
fun get_type_infos ctxt =
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    26
    maps collect_Tcons
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    27
    #> distinct (op =)
54401
f6950854855d ported 'Simps_Case_Conv' to use new 'Ctr_Sugar' abstraction
blanchet
parents: 53433
diff changeset
    28
    #> map_filter (Ctr_Sugar.ctr_sugar_of ctxt)
60702
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    29
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    30
fun get_split_ths ctxt = get_type_infos ctxt #> map #split
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    31
59582
0fbed69ff081 tuned signature -- prefer qualified names;
wenzelm
parents: 59580
diff changeset
    32
val strip_eq = Thm.prop_of #> HOLogic.dest_Trueprop #> HOLogic.dest_eq
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    33
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    34
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    35
local
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    36
53429
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    37
  fun transpose [] = []
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    38
    | transpose ([] :: xss) = transpose xss
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    39
    | transpose xss = map hd xss :: transpose (map tl xss);
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    40
60702
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    41
  fun same_fun single_ctrs (ts as _ $ _ :: _) =
53429
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    42
      let
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    43
        val (fs, argss) = map strip_comb ts |> split_list
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    44
        val f = hd fs
60702
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    45
        fun is_single_ctr (Const (name, _)) = member (op =) single_ctrs name
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    46
          | is_single_ctr _ = false
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    47
      in if not (is_single_ctr f) andalso forall (fn x => f = x) fs then SOME (f, argss) else NONE end
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    48
    | same_fun _ _ = NONE
53429
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    49
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    50
  (* pats must be non-empty *)
60702
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    51
  fun split_pat single_ctrs pats ctxt =
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    52
      case same_fun single_ctrs pats of
53429
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    53
        NONE =>
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    54
          let
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    55
            val (name, ctxt') = yield_singleton Variable.variant_fixes "x" ctxt
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    56
            val var = Free (name, fastype_of (hd pats))
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    57
          in (((var, [var]), map single pats), ctxt') end
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    58
      | SOME (f, argss) =>
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    59
          let
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    60
            val (((def_pats, def_frees), case_patss), ctxt') =
60702
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    61
              split_pats single_ctrs argss ctxt
53429
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    62
            val def_pat = list_comb (f, def_pats)
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    63
          in (((def_pat, flat def_frees), case_patss), ctxt') end
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    64
  and
60702
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    65
      split_pats single_ctrs patss ctxt =
53429
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    66
        let
60702
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    67
          val (splitted, ctxt') = fold_map (split_pat single_ctrs) (transpose patss) ctxt
53429
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    68
          val r = splitted |> split_list |> apfst split_list |> apsnd (transpose #> map flat)
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    69
        in (r, ctxt') end
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    70
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    71
(*
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    72
  Takes a list lhss of left hand sides (which are lists of patterns)
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    73
  and a list rhss of right hand sides. Returns
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    74
    - a single equation with a (nested) case-expression on the rhs
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    75
    - a list of all split-thms needed to split the rhs
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    76
  Patterns which have the same outer context in all lhss remain
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    77
  on the lhs of the computed equation.
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    78
*)
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    79
fun build_case_t fun_t lhss rhss ctxt =
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    80
  let
60702
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    81
    val single_ctrs =
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    82
      get_type_infos ctxt (map fastype_of (flat lhss))
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    83
      |> map_filter (fn ti => case #ctrs ti of [Const (name, _)] => SOME name | _ => NONE)
53429
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    84
    val (((def_pats, def_frees), case_patss), ctxt') =
60702
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    85
      split_pats single_ctrs lhss ctxt
53429
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    86
    val pattern = map HOLogic.mk_tuple case_patss
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    87
    val case_arg = HOLogic.mk_tuple (flat def_frees)
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    88
    val cases = Case_Translation.make_case ctxt' Case_Translation.Warning Name.context
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    89
      case_arg (pattern ~~ rhss)
60702
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
    90
    val split_thms = get_split_ths ctxt' [fastype_of case_arg]
53429
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    91
    val t = (list_comb (fun_t, def_pats), cases)
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    92
      |> HOLogic.mk_eq
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    93
      |> HOLogic.mk_Trueprop
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
    94
  in ((t, split_thms), ctxt') end
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    95
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    96
fun tac ctxt {splits, intros, defs} =
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    97
  let val ctxt' = Classical.addSIs (ctxt, intros) in
58956
a816aa3ff391 proper context for compose_tac, Splitter.split_tac (relevant for unify trace options);
wenzelm
parents: 58028
diff changeset
    98
    REPEAT_DETERM1 (FIRSTGOAL (split_tac ctxt splits))
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
    99
    THEN Local_Defs.unfold_tac ctxt defs
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   100
    THEN safe_tac ctxt'
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   101
  end
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   102
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   103
fun import [] ctxt = ([], ctxt)
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   104
  | import (thm :: thms) ctxt =
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   105
    let
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   106
      val fun_ct = strip_eq #> fst #> strip_comb #> fst #> Logic.mk_term
59621
291934bac95e Thm.cterm_of and Thm.ctyp_of operate on local context;
wenzelm
parents: 59582
diff changeset
   107
        #> Thm.cterm_of ctxt
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   108
      val ct = fun_ct thm
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   109
      val cts = map fun_ct thms
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   110
      val pairs = map (fn s => (s,ct)) cts
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   111
      val thms' = map (fn (th,p) => Thm.instantiate (Thm.match p) th) (thms ~~ pairs)
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   112
    in Variable.import true (thm :: thms') ctxt |> apfst snd end
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   113
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   114
in
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   115
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   116
(*
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   117
  For a list
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   118
    f p_11 ... p_1n = t1
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   119
    f p_21 ... p_2n = t2
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   120
    ...
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   121
    f p_mn ... p_mn = tm
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   122
  of theorems, prove a single theorem
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   123
    f x1 ... xn = t
53429
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
   124
  where t is a (nested) case expression. f must not be a function
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
   125
  application. Moreover, the terms p_11, ..., p_mn must be non-overlapping
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
   126
  datatype patterns. The patterns must be exhausting up to common constructor
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
   127
  contexts.
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   128
*)
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   129
fun to_case ctxt ths =
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   130
  let
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   131
    val (iths, ctxt') = import ths ctxt
53429
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
   132
    val fun_t = hd iths |> strip_eq |> fst |> head_of
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   133
    val eqs = map (strip_eq #> apfst (snd o strip_comb)) iths
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   134
59650
wenzelm
parents: 59621
diff changeset
   135
    fun hide_rhs ((pat, rhs), name) lthy =
wenzelm
parents: 59621
diff changeset
   136
      let
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   137
        val frees = fold Term.add_frees pat []
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   138
        val abs_rhs = fold absfree frees rhs
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   139
        val ((f,def), lthy') = Local_Defs.add_def
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   140
          ((Binding.name name, Mixfix.NoSyn), abs_rhs) lthy
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   141
      in ((list_comb (f, map Free (rev frees)), def), lthy') end
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   142
59650
wenzelm
parents: 59621
diff changeset
   143
    val ((def_ts, def_thms), ctxt2) =
wenzelm
parents: 59621
diff changeset
   144
      let val names = Name.invent (Variable.names_of ctxt') "rhs" (length eqs)
53429
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
   145
      in fold_map hide_rhs (eqs ~~ names) ctxt' |> apfst split_list end
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   146
53429
9d9945941eab allowed less exhaustive patterns
noschinl
parents: 53426
diff changeset
   147
    val ((t, split_thms), ctxt3) = build_case_t fun_t (map fst eqs) def_ts ctxt2
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   148
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   149
    val th = Goal.prove ctxt3 [] [] t (fn {context=ctxt, ...} =>
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   150
          tac ctxt {splits=split_thms, intros=ths, defs=def_thms})
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   151
  in th
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   152
    |> singleton (Proof_Context.export ctxt3 ctxt)
54883
dd04a8b654fc proper context for norm_hhf and derived operations;
wenzelm
parents: 54401
diff changeset
   153
    |> Goal.norm_result ctxt
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   154
  end
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   155
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   156
end
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   157
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   158
local
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   159
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   160
fun was_split t =
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   161
  let
56252
b72e0a9d62b9 more antiquotations;
wenzelm
parents: 55997
diff changeset
   162
    val is_free_eq_imp = is_Free o fst o HOLogic.dest_eq o fst o HOLogic.dest_imp
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   163
    val get_conjs = HOLogic.dest_conj o HOLogic.dest_Trueprop
56252
b72e0a9d62b9 more antiquotations;
wenzelm
parents: 55997
diff changeset
   164
    fun dest_alls (Const (@{const_name All}, _) $ Abs (_, _, t)) = dest_alls t
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   165
      | dest_alls t = t
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   166
  in forall (is_free_eq_imp o dest_alls) (get_conjs t) end
56252
b72e0a9d62b9 more antiquotations;
wenzelm
parents: 55997
diff changeset
   167
  handle TERM _ => false
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   168
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   169
fun apply_split ctxt split thm = Seq.of_list
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   170
  let val ((_,thm'), ctxt') = Variable.import false [thm] ctxt in
59582
0fbed69ff081 tuned signature -- prefer qualified names;
wenzelm
parents: 59580
diff changeset
   171
    (Variable.export ctxt' ctxt) (filter (was_split o Thm.prop_of) (thm' RL [split]))
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   172
  end
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   173
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   174
fun forward_tac rules t = Seq.of_list ([t] RL rules)
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   175
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   176
val refl_imp = refl RSN (2, mp)
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   177
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   178
val get_rules_once_split =
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   179
  REPEAT (forward_tac [conjunct1, conjunct2])
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   180
    THEN REPEAT (forward_tac [spec])
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   181
    THEN (forward_tac [refl_imp])
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   182
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   183
fun do_split ctxt split =
60355
ccafd7d193e7 simps_of_case: Better error if split rule is not an equality
noschinl
parents: 60354
diff changeset
   184
  case try op RS (split, iffD1) of
ccafd7d193e7 simps_of_case: Better error if split rule is not an equality
noschinl
parents: 60354
diff changeset
   185
    NONE => raise TERM ("malformed split rule", [Thm.prop_of split])
ccafd7d193e7 simps_of_case: Better error if split rule is not an equality
noschinl
parents: 60354
diff changeset
   186
  | SOME split' =>
ccafd7d193e7 simps_of_case: Better error if split rule is not an equality
noschinl
parents: 60354
diff changeset
   187
      let val split_rhs = Thm.concl_of (hd (snd (fst (Variable.import false [split'] ctxt))))
ccafd7d193e7 simps_of_case: Better error if split rule is not an equality
noschinl
parents: 60354
diff changeset
   188
      in if was_split split_rhs
ccafd7d193e7 simps_of_case: Better error if split rule is not an equality
noschinl
parents: 60354
diff changeset
   189
         then DETERM (apply_split ctxt split') THEN get_rules_once_split
ccafd7d193e7 simps_of_case: Better error if split rule is not an equality
noschinl
parents: 60354
diff changeset
   190
         else raise TERM ("malformed split rule", [split_rhs])
ccafd7d193e7 simps_of_case: Better error if split rule is not an equality
noschinl
parents: 60354
diff changeset
   191
      end
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   192
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   193
val atomize_meta_eq = forward_tac [meta_eq_to_obj_eq]
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   194
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   195
in
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   196
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   197
fun gen_to_simps ctxt splitthms thm =
60354
235d65be79c9 simps_of_case: allow Drule.dummy_thm as ignored split rule
noschinl
parents: 59936
diff changeset
   198
  let val splitthms' = filter (fn t => not (Thm.eq_thm (t, Drule.dummy_thm))) splitthms
235d65be79c9 simps_of_case: allow Drule.dummy_thm as ignored split rule
noschinl
parents: 59936
diff changeset
   199
  in
235d65be79c9 simps_of_case: allow Drule.dummy_thm as ignored split rule
noschinl
parents: 59936
diff changeset
   200
    Seq.list_of ((TRY atomize_meta_eq THEN (REPEAT (FIRST (map (do_split ctxt) splitthms')))) thm)
235d65be79c9 simps_of_case: allow Drule.dummy_thm as ignored split rule
noschinl
parents: 59936
diff changeset
   201
  end
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   202
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   203
fun to_simps ctxt thm =
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   204
  let
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   205
    val T = thm |> strip_eq |> fst |> strip_comb |> fst |> fastype_of
60702
5e03e1bd1be0 case_of_simps: do not split for types with a single constructor
noschinl
parents: 60355
diff changeset
   206
    val splitthms = get_split_ths ctxt [T]
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   207
  in gen_to_simps ctxt splitthms thm end
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   208
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   209
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   210
end
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   211
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   212
fun case_of_simps_cmd (bind, thms_ref) lthy =
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   213
  let
55997
9dc5ce83202c modernized Attrib.check_name/check_src similar to methods (see also a989bdaf8121);
wenzelm
parents: 54883
diff changeset
   214
    val bind' = apsnd (map (Attrib.check_src lthy)) bind
61813
wenzelm
parents: 60702
diff changeset
   215
    val thm = Attrib.eval_thms lthy thms_ref |> to_case lthy
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   216
  in
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   217
    Local_Theory.note (bind', [thm]) lthy |> snd
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   218
  end
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   219
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   220
fun simps_of_case_cmd ((bind, thm_ref), splits_ref) lthy =
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   221
  let
55997
9dc5ce83202c modernized Attrib.check_name/check_src similar to methods (see also a989bdaf8121);
wenzelm
parents: 54883
diff changeset
   222
    val bind' = apsnd (map (Attrib.check_src lthy)) bind
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   223
    val thm = singleton (Attrib.eval_thms lthy) thm_ref
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   224
    val simps = if null splits_ref
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   225
      then to_simps lthy thm
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   226
      else gen_to_simps lthy (Attrib.eval_thms lthy splits_ref) thm
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   227
  in
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   228
    Local_Theory.note (bind', simps) lthy |> snd
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   229
  end
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   230
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   231
val _ =
59936
b8ffc3dc9e24 @{command_spec} is superseded by @{command_keyword};
wenzelm
parents: 59650
diff changeset
   232
  Outer_Syntax.local_theory @{command_keyword case_of_simps}
57628
c80fc5576271 tuned message;
wenzelm
parents: 56252
diff changeset
   233
    "turn a list of equations into a case expression"
62969
9f394a16c557 eliminated "xname" and variants;
wenzelm
parents: 61813
diff changeset
   234
    (Parse_Spec.opt_thm_name ":"  -- Parse.thms1 >> case_of_simps_cmd)
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   235
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   236
val parse_splits = @{keyword "("} |-- Parse.reserved "splits" |-- @{keyword ":"} |--
62969
9f394a16c557 eliminated "xname" and variants;
wenzelm
parents: 61813
diff changeset
   237
  Parse.thms1 --| @{keyword ")"}
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   238
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   239
val _ =
59936
b8ffc3dc9e24 @{command_spec} is superseded by @{command_keyword};
wenzelm
parents: 59650
diff changeset
   240
  Outer_Syntax.local_theory @{command_keyword simps_of_case}
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   241
    "perform case split on rule"
62969
9f394a16c557 eliminated "xname" and variants;
wenzelm
parents: 61813
diff changeset
   242
    (Parse_Spec.opt_thm_name ":"  -- Parse.thm --
53426
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   243
      Scan.optional parse_splits [] >> simps_of_case_cmd)
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   244
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   245
end
92db671e0ac6 added simps_of_case and case_of_simps to convert between simps and case rules
noschinl
parents:
diff changeset
   246