File ‹Cancellation/cancel.ML›
signature CANCEL =
sig
  val proc: Simplifier.proc
end;
functor Cancel_Fun(Data: CANCEL_NUMERALS_DATA): CANCEL =
struct
structure Cancel_Numerals_Fun = CancelNumeralsFun(open Data)
exception SORT_NOT_GENERAL_ENOUGH of string * typ * term
fun proc ctxt ct =
  let
    val t = Thm.term_of ct
    val (t', ctxt') = yield_singleton (Variable.import_terms true) t ctxt
    val pre_simplified_ct =
      Simplifier.full_rewrite (clear_simpset ctxt
        addsimps Named_Theorems.get ctxt \<^named_theorems>‹cancelation_simproc_pre›
        |> Simplifier.add_proc \<^simproc>‹NO_MATCH›) (Thm.cterm_of ctxt t');
    val t' = Thm.term_of (Thm.rhs_of pre_simplified_ct)
    val export = singleton (Variable.export ctxt' ctxt)
    val (t1,_) = Data.dest_bal t'
    val sort_not_general_enough = ((fastype_of t1) = \<^typ>‹nat›) orelse
        Sorts.of_sort (Sign.classes_of (Proof_Context.theory_of ctxt))
         (fastype_of t1, \<^sort>‹comm_ring_1›)
    val _ =
       if sort_not_general_enough
       then raise SORT_NOT_GENERAL_ENOUGH("type too precise, another simproc should do the job",
          fastype_of t1, t1)
       else ()
    val canceled_thm = Cancel_Numerals_Fun.proc ctxt (Thm.rhs_of pre_simplified_ct)
    fun add_pre_simplification thm = @{thm Pure.transitive} OF [pre_simplified_ct, thm]
    fun add_post_simplification thm =
      let val post_simplified_ct =
        Simplifier.full_rewrite (clear_simpset ctxt
          addsimps Named_Theorems.get ctxt \<^named_theorems>‹cancelation_simproc_post›
          |> Simplifier.add_proc \<^simproc>‹NO_MATCH›) (Thm.rhs_of thm)
      in @{thm Pure.transitive} OF [thm, post_simplified_ct] end
  in
    Option.map (export o add_post_simplification o add_pre_simplification) canceled_thm
  end
  
  handle TERM _ => NONE
       | TYPE _ => NONE
       | SORT_NOT_GENERAL_ENOUGH _ => NONE
end;