Quot/quotient_term.ML
changeset 758 3104d62e7a16
child 760 c1989de100b4
equal deleted inserted replaced
757:c129354f2ff6 758:3104d62e7a16
       
     1 signature QUOTIENT_TERM =
       
     2 sig
       
     3     val regularize_trm: Proof.context -> term -> term -> term
       
     4     val inj_repabs_trm: Proof.context -> (term * term) -> term
       
     5 end;
       
     6 
       
     7 structure Quotient_Term: QUOTIENT_TERM =
       
     8 struct
       
     9 
       
    10 (*
       
    11 Regularizing an rtrm means:
       
    12  
       
    13  - Quantifiers over a type that need lifting are replaced 
       
    14    by bounded quantifiers, for example:
       
    15 
       
    16       All P  ===> All (Respects R) P
       
    17 
       
    18    where the relation R is given by the rty and qty;
       
    19  
       
    20  - Abstractions over a type that needs lifting are replaced
       
    21    by bounded abstractions:
       
    22       
       
    23       %x. P  ===> Ball (Respects R) %x. P
       
    24 
       
    25  - Equalities over the type being lifted are replaced by
       
    26    corresponding equivalence relations:
       
    27 
       
    28       A = B  ===> R A B
       
    29 
       
    30    or 
       
    31 
       
    32       A = B  ===> (R ===> R) A B
       
    33  
       
    34    for more complicated types of A and B
       
    35 *)
       
    36 
       
    37 (* builds the relation that is the argument of respects *)
       
    38 fun mk_resp_arg lthy (rty, qty) =
       
    39 let
       
    40   val thy = ProofContext.theory_of lthy
       
    41 in  
       
    42   if rty = qty
       
    43   then HOLogic.eq_const rty
       
    44   else
       
    45     case (rty, qty) of
       
    46       (Type (s, tys), Type (s', tys')) =>
       
    47        if s = s' 
       
    48        then let
       
    49               val SOME map_info = maps_lookup thy s
       
    50               (* FIXME dont return an option, raise an exception *)
       
    51               val args = map (mk_resp_arg lthy) (tys ~~ tys')
       
    52             in
       
    53               list_comb (Const (#relfun map_info, dummyT), args) 
       
    54             end  
       
    55        else let  
       
    56               val SOME qinfo = quotdata_lookup_thy thy s'
       
    57               (* FIXME: check in this case that the rty and qty *)
       
    58               (* FIXME: correspond to each other *)
       
    59               val (s, _) = dest_Const (#rel qinfo)
       
    60               (* FIXME: the relation should only be the string        *)
       
    61               (* FIXME: and the type needs to be calculated as below; *)
       
    62               (* FIXME: maybe one should actually have a term         *)
       
    63               (* FIXME: and one needs to force it to have this type   *)
       
    64             in
       
    65               Const (s, rty --> rty --> @{typ bool})
       
    66             end
       
    67       | _ => HOLogic.eq_const dummyT 
       
    68              (* FIXME: check that the types correspond to each other? *)
       
    69 end
       
    70 
       
    71 val mk_babs = Const (@{const_name Babs}, dummyT)
       
    72 val mk_ball = Const (@{const_name Ball}, dummyT)
       
    73 val mk_bex  = Const (@{const_name Bex}, dummyT)
       
    74 val mk_resp = Const (@{const_name Respects}, dummyT)
       
    75 
       
    76 (* - applies f to the subterm of an abstraction,   *)
       
    77 (*   otherwise to the given term,                  *)
       
    78 (* - used by regularize, therefore abstracted      *)
       
    79 (*   variables do not have to be treated specially *)
       
    80 fun apply_subt f trm1 trm2 =
       
    81   case (trm1, trm2) of
       
    82     (Abs (x, T, t), Abs (_ , _, t')) => Abs (x, T, f t t')
       
    83   | _ => f trm1 trm2
       
    84 
       
    85 (* the major type of All and Ex quantifiers *)
       
    86 fun qnt_typ ty = domain_type (domain_type ty)  
       
    87 
       
    88 
       
    89 (* produces a regularized version of rtrm       *)
       
    90 (*                                              *)
       
    91 (* - the result is still contains dummyT        *)
       
    92 (*                                              *)
       
    93 (* - for regularisation we do not need any      *)
       
    94 (*   special treatment of bound variables       *)
       
    95 
       
    96 fun regularize_trm lthy rtrm qtrm =
       
    97   case (rtrm, qtrm) of
       
    98     (Abs (x, ty, t), Abs (_, ty', t')) =>
       
    99        let
       
   100          val subtrm = Abs(x, ty, regularize_trm lthy t t')
       
   101        in
       
   102          if ty = ty' then subtrm
       
   103          else mk_babs $ (mk_resp $ mk_resp_arg lthy (ty, ty')) $ subtrm
       
   104        end
       
   105 
       
   106   | (Const (@{const_name "All"}, ty) $ t, Const (@{const_name "All"}, ty') $ t') =>
       
   107        let
       
   108          val subtrm = apply_subt (regularize_trm lthy) t t'
       
   109        in
       
   110          if ty = ty' then Const (@{const_name "All"}, ty) $ subtrm
       
   111          else mk_ball $ (mk_resp $ mk_resp_arg lthy (qnt_typ ty, qnt_typ ty')) $ subtrm
       
   112        end
       
   113 
       
   114   | (Const (@{const_name "Ex"}, ty) $ t, Const (@{const_name "Ex"}, ty') $ t') =>
       
   115        let
       
   116          val subtrm = apply_subt (regularize_trm lthy) t t'
       
   117        in
       
   118          if ty = ty' then Const (@{const_name "Ex"}, ty) $ subtrm
       
   119          else mk_bex $ (mk_resp $ mk_resp_arg lthy (qnt_typ ty, qnt_typ ty')) $ subtrm
       
   120        end
       
   121 
       
   122   | (* equalities need to be replaced by appropriate equivalence relations *) 
       
   123     (Const (@{const_name "op ="}, ty), Const (@{const_name "op ="}, ty')) =>
       
   124          if ty = ty' then rtrm
       
   125          else mk_resp_arg lthy (domain_type ty, domain_type ty') 
       
   126 
       
   127   | (* in this case we check whether the given equivalence relation is correct *) 
       
   128     (rel, Const (@{const_name "op ="}, ty')) =>
       
   129        let 
       
   130          val exc = LIFT_MATCH "regularise (relation mismatch)"
       
   131          val rel_ty = (fastype_of rel) handle TERM _ => raise exc 
       
   132          val rel' = mk_resp_arg lthy (domain_type rel_ty, domain_type ty') 
       
   133        in 
       
   134          if rel' = rel then rtrm else raise exc
       
   135        end  
       
   136 
       
   137   | (_, Const _) =>
       
   138        let 
       
   139          fun same_name (Const (s, T)) (Const (s', T')) = (s = s') (*andalso (T = T')*)
       
   140            | same_name _ _ = false
       
   141           (* TODO/FIXME: This test is not enough. *) 
       
   142           (*             Why?                     *)
       
   143           (* Because constants can have the same name but not be the same
       
   144              constant.  All overloaded constants have the same name but because
       
   145              of different types they do differ.
       
   146         
       
   147              This code will let one write a theorem where plus on nat is
       
   148              matched to plus on int, even if the latter is defined differently.
       
   149     
       
   150              This would result in hard to understand failures in injection and
       
   151              cleaning. *)
       
   152            (* cu: if I also test the type, then something else breaks *)
       
   153        in
       
   154          if same_name rtrm qtrm then rtrm
       
   155          else 
       
   156            let 
       
   157              val thy = ProofContext.theory_of lthy
       
   158              val qtrm_str = Syntax.string_of_term lthy qtrm
       
   159              val exc1 = LIFT_MATCH ("regularize (constant " ^ qtrm_str ^ " not found)")
       
   160              val exc2 = LIFT_MATCH ("regularize (constant " ^ qtrm_str ^ " mismatch)")
       
   161              val rtrm' = (#rconst (qconsts_lookup thy qtrm)) handle NotFound => raise exc1
       
   162            in 
       
   163              if Pattern.matches thy (rtrm', rtrm) 
       
   164              then rtrm else raise exc2
       
   165            end
       
   166        end 
       
   167 
       
   168   | (t1 $ t2, t1' $ t2') =>
       
   169        (regularize_trm lthy t1 t1') $ (regularize_trm lthy t2 t2')
       
   170 
       
   171   | (Free (x, ty), Free (x', ty')) => 
       
   172        (* this case cannot arrise as we start with two fully atomized terms *)
       
   173        raise (LIFT_MATCH "regularize (frees)")
       
   174 
       
   175   | (Bound i, Bound i') =>
       
   176        if i = i' then rtrm 
       
   177        else raise (LIFT_MATCH "regularize (bounds mismatch)")
       
   178 
       
   179   | _ =>
       
   180        let 
       
   181          val rtrm_str = Syntax.string_of_term lthy rtrm
       
   182          val qtrm_str = Syntax.string_of_term lthy qtrm
       
   183        in
       
   184          raise (LIFT_MATCH ("regularize failed (default: " ^ rtrm_str ^ "," ^ qtrm_str ^ ")"))
       
   185        end
       
   186 
       
   187 
       
   188 
       
   189 (*
       
   190 Injecting of Rep/Abs means:
       
   191 
       
   192   For abstractions
       
   193 :
       
   194   * If the type of the abstraction doesn't need lifting we recurse.
       
   195 
       
   196   * If it needs lifting then we add Rep/Abs around the whole term and 
       
   197     check if the bound variable needs lifting.
       
   198  
       
   199     * If it does we recurse and put Rep/Abs around all occurences
       
   200       of the variable in the obtained subterm. This in combination
       
   201       with the Rep/Abs from above will let us change the type of 
       
   202       the abstraction with rewriting.
       
   203   
       
   204   For applications:
       
   205   
       
   206   * If the term is Respects applied to anything we leave it unchanged
       
   207 
       
   208   * If the term needs lifting and the head is a constant that we know
       
   209     how to lift, we put a Rep/Abs and recurse
       
   210 
       
   211   * If the term needs lifting and the head is a Free applied to subterms
       
   212     (if it is not applied we treated it in Abs branch) then we
       
   213     put Rep/Abs and recurse
       
   214 
       
   215   * Otherwise just recurse.
       
   216 *)
       
   217 
       
   218 fun mk_repabs lthy (T, T') trm = 
       
   219   Quotient_Def.get_fun repF lthy (T, T') 
       
   220     $ (Quotient_Def.get_fun absF lthy (T, T') $ trm)
       
   221 
       
   222 
       
   223 (* bound variables need to be treated properly,     *)
       
   224 (* as the type of subterms needs to be calculated   *)
       
   225 
       
   226 fun inj_repabs_trm lthy (rtrm, qtrm) =
       
   227  case (rtrm, qtrm) of
       
   228     (Const (@{const_name "Ball"}, T) $ r $ t, Const (@{const_name "All"}, _) $ t') =>
       
   229        Const (@{const_name "Ball"}, T) $ r $ (inj_repabs_trm lthy (t, t'))
       
   230 
       
   231   | (Const (@{const_name "Bex"}, T) $ r $ t, Const (@{const_name "Ex"}, _) $ t') =>
       
   232        Const (@{const_name "Bex"}, T) $ r $ (inj_repabs_trm lthy (t, t'))
       
   233 
       
   234   | (Const (@{const_name "Babs"}, T) $ r $ t, t' as (Abs _)) =>
       
   235       let
       
   236         val rty = fastype_of rtrm
       
   237         val qty = fastype_of qtrm
       
   238       in
       
   239         mk_repabs lthy (rty, qty) (Const (@{const_name "Babs"}, T) $ r $ (inj_repabs_trm lthy (t, t')))
       
   240       end
       
   241 
       
   242   | (Abs (x, T, t), Abs (x', T', t')) =>
       
   243       let
       
   244         val rty = fastype_of rtrm
       
   245         val qty = fastype_of qtrm
       
   246         val (y, s) = Term.dest_abs (x, T, t)
       
   247         val (_, s') = Term.dest_abs (x', T', t')
       
   248         val yvar = Free (y, T)
       
   249         val result = Term.lambda_name (y, yvar) (inj_repabs_trm lthy (s, s'))
       
   250       in
       
   251         if rty = qty then result
       
   252         else mk_repabs lthy (rty, qty) result
       
   253       end
       
   254 
       
   255   | (t $ s, t' $ s') =>  
       
   256        (inj_repabs_trm lthy (t, t')) $ (inj_repabs_trm lthy (s, s'))
       
   257 
       
   258   | (Free (_, T), Free (_, T')) => 
       
   259         if T = T' then rtrm 
       
   260         else mk_repabs lthy (T, T') rtrm
       
   261 
       
   262   | (_, Const (@{const_name "op ="}, _)) => rtrm
       
   263 
       
   264   | (_, Const (_, T')) =>
       
   265       let
       
   266         val rty = fastype_of rtrm
       
   267       in 
       
   268         if rty = T' then rtrm
       
   269         else mk_repabs lthy (rty, T') rtrm
       
   270       end   
       
   271   
       
   272   | _ => raise (LIFT_MATCH "injection")
       
   273 
       
   274 end; (* structure *)
       
   275 
       
   276 open Quotient_Term;
       
   277 
       
   278