File ‹Tools/cartprod.ML›
signature FP =          
  sig
  val oper      : term                  
  val bnd_mono  : term                  
  val bnd_monoI : thm                   
  val subs      : thm                   
  val Tarski    : thm                   
  val induct    : thm                   
  end;
signature SU =                  
  sig
  val sum       : term                  
  val inl       : term                  
  val inr       : term                  
  val elim      : term                  
  val case_inl  : thm                   
  val case_inr  : thm                   
  val inl_iff   : thm                   
  val inr_iff   : thm                   
  val distinct  : thm                   
  val distinct' : thm                   
  val free_SEs  : thm list              
  end;
signature PR =                  
  sig
  val sigma     : term                  
  val pair      : term                  
  val split_name : string               
  val pair_iff  : thm                   
  val split_eq  : thm                   
  val fsplitI   : thm                   
  val fsplitD   : thm                   
  val fsplitE   : thm                   
  end;
signature CARTPROD =            
  sig
  val ap_split : typ -> typ -> term -> term
  val factors : typ -> typ list
  val mk_prod : typ * typ -> typ
  val mk_tuple : term -> typ -> term list -> term
  val pseudo_type : term -> typ
  val remove_split : Proof.context -> thm -> thm
  val split_const : typ -> term
  val split_rule_var : Proof.context -> term * typ * thm -> thm
  end;
functor CartProd_Fun (Pr: PR) : CARTPROD =
struct
fun mk_prod (T1,T2) = Type("*", [T1,T2]);
fun pseudo_type (t $ A $ Abs(_,_,B)) = 
      if t = Pr.sigma
      then mk_prod(pseudo_type A, pseudo_type B)
      else \<^Type>‹i›
  | pseudo_type _ = \<^Type>‹i›;
fun factors (Type("*", [T1, T2])) = factors T1 @ factors T2
  | factors T                     = [T];
fun split_const T = Const(Pr.split_name, [[\<^Type>‹i›, \<^Type>‹i›]--->T, \<^Type>‹i›] ---> T);
fun ap_split (Type("*", [T1,T2])) T3 u   = 
       split_const T3 $ 
       Abs("v", \<^Type>‹i›, 
           ap_split T2 T3
           ((ap_split T1 (factors T2 ---> T3) (incr_boundvars 1 u)) $ 
            Bound 0))
  | ap_split T T3 u = u;
fun mk_tuple pair (Type("*", [T1,T2])) tms = 
        pair $ mk_tuple pair T1 tms
             $ mk_tuple pair T2 (drop (length (factors T1)) tms)
  | mk_tuple pair T (t::_) = t;
fun remove_split ctxt = rewrite_rule ctxt [Pr.split_eq];
fun split_rule_var ctxt (Var(v,_), Type("fun",[T1,T2]), rl) =
      let val T' = factors T1 ---> T2
          val newt = ap_split T1 T2 (Var(v,T'))
      in
        remove_split ctxt
          (Drule.instantiate_normalize (TVars.empty,
            Vars.make1 ((v, \<^Type>‹i› --> T2), Thm.cterm_of ctxt newt)) rl)
      end
  | split_rule_var _ (t,T,rl) = rl;
end;