diff options
-rw-r--r-- | contrib/subtac/equations.ml4 | 433 | ||||
-rw-r--r-- | proofs/logic.ml | 2 | ||||
-rw-r--r-- | test-suite/success/Equations.v | 105 | ||||
-rw-r--r-- | theories/Program/Equality.v | 170 | ||||
-rw-r--r-- | theories/Program/Tactics.v | 35 |
5 files changed, 529 insertions, 216 deletions
diff --git a/contrib/subtac/equations.ml4 b/contrib/subtac/equations.ml4 index 14330e72e..f3f0e052b 100644 --- a/contrib/subtac/equations.ml4 +++ b/contrib/subtac/equations.ml4 @@ -37,21 +37,27 @@ open Libnames type pat = | PRel of int | PCstr of constructor * pat list - | PInnac of constr - -let rec constr_of_pat = function + | PInac of constr + +let coq_inacc = lazy (Coqlib.gen_constant "equations" ["Program";"Equality"] "inaccessible_pattern") + +let mkInac env c = + mkApp (Lazy.force coq_inacc, [| Typing.type_of env Evd.empty c ; c |]) + +let rec constr_of_pat ?(inacc=true) env = function | PRel i -> mkRel i | PCstr (c, p) -> let c' = mkConstruct c in - mkApp (c', Array.of_list (constrs_of_pats p)) - | PInnac r -> r + mkApp (c', Array.of_list (constrs_of_pats ~inacc env p)) + | PInac r -> + if inacc then try mkInac env r with _ -> r else r -and constrs_of_pats l = map constr_of_pat l +and constrs_of_pats ?(inacc=true) env l = map (constr_of_pat ~inacc env) l let rec pat_vars = function | PRel i -> Intset.singleton i | PCstr (c, p) -> pats_vars p - | PInnac _ -> Intset.empty + | PInac _ -> Intset.empty and pats_vars l = fold_left (fun vars p -> @@ -67,32 +73,51 @@ let rec pats_of_constrs l = map pat_of_constr l and pat_of_constr c = match kind_of_term c with | Rel i -> PRel i - | App (f, args) when isConstruct f -> + | App (f, [| a ; c |]) when eq_constr f (Lazy.force coq_inacc) -> + PInac c + | App (f, args) when isConstruct f -> PCstr (destConstruct f, pats_of_constrs (Array.to_list args)) | Construct f -> PCstr (f, []) - | _ -> PInnac c + | _ -> PInac c -let innacs_of_constrs l = map (fun x -> PInnac x) l +let inaccs_of_constrs l = map (fun x -> PInac x) l exception Conflict let rec pmatch p c = - match p, kind_of_term c with - | PRel i, t -> [i, c] - | PCstr (c, pl), App (c', l') when kind_of_term c' = Construct c -> - pmatches pl (Array.to_list l') - | PCstr (c, []), Construct c' when c' = c -> [] - | PInnac _, _ -> [] - | _, _ -> raise Conflict + match p, c with + | PRel i, t -> true +(* | _, PRel i -> true *) + | PCstr (c, pl), PCstr (c', pl') when c = c' -> pmatches pl pl' + | PInac _, _ -> true + | _, _ -> false and pmatches pl l = match pl, l with - | [], [] -> [] - | hd :: tl, hd' :: tl' -> pmatch hd hd' @ pmatches tl tl' - | _ -> raise Conflict + | [], [] -> true + | hd :: tl, hd' :: tl' -> pmatch hd hd' && pmatches tl tl' + | _ -> false let pattern_matches pl l = pmatches pl l +(* let rec pmatch p c = *) +(* match p, kind_of_term c with *) +(* | PRel i, t -> true *) +(* | t, Rel n -> true *) +(* | PCstr (c, pl), App (c', l') when kind_of_term c' = Construct c -> *) +(* pmatches pl (Array.to_list l') *) +(* | PCstr (c, []), Construct c' when c' = c -> true *) +(* | PInac _, _ -> true *) +(* | _, _ -> false *) + +(* and pmatches pl l = *) +(* match pl, l with *) +(* | [], [] -> true *) +(* | hd :: tl, hd' :: tl' -> pmatch hd hd' && pmatches tl tl' *) +(* | _ -> false *) + +(* let pattern_matches pl l = pmatches pl l *) + (** Specialize by a substitution. *) let subst_tele s = replace_vars (List.map (fun (id, _, t) -> id, t) s) @@ -129,30 +154,30 @@ let rec lift_pat n k p = if i >= k then PRel (i + n) else p | PCstr(c, pl) -> PCstr (c, lift_pats n k pl) - | PInnac r -> PInnac (liftn n k r) + | PInac r -> PInac (liftn n k r) and lift_pats n k = map (lift_pat n k) -let rec subst_pat k t p = +let rec subst_pat env k t p = match p with | PRel i -> if i = k then t else if i > k then PRel (pred i) else p | PCstr(c, pl) -> - PCstr (c, subst_pats k t pl) - | PInnac r -> PInnac (substnl [constr_of_pat t] k r) + PCstr (c, subst_pats env k t pl) + | PInac r -> PInac (substnl [constr_of_pat ~inacc:false env t] (pred k) r) -and subst_pats k t = map (subst_pat k t) +and subst_pats env k t = map (subst_pat env k t) let rec specialize s p = match p with | PRel i -> - if mem_assoc i s then PInnac (assoc i s) + if mem_assoc i s then PInac (assoc i s) else p | PCstr(c, pl) -> PCstr (c, specialize_pats s pl) - | PInnac r -> PInnac (specialize_constr s r) + | PInac r -> PInac (specialize_constr s r) and specialize_constr s c = subst_rel_subst 0 s c and specialize_pats s = map (specialize s) @@ -170,36 +195,34 @@ type program = and signature = identifier * rel_context * constr -and clause = rel_context * constr list * (constr, identifier located) rhs +and clause = lhs * (constr, int) rhs -and lhs = pat list +and lhs = rel_context * identifier * pat list and ('a, 'b) rhs = | Program of 'a | Empty of 'b type splitting = - | Compute of rel_context * lhs * (constr, int) rhs - | Split of rel_context * lhs * int * inductive_family * + | Compute of clause + | Split of lhs * int * inductive_family * unification_result array * splitting option array - + and unification_result = - rel_context * rel_context * constr * pat * substitution option + rel_context * int * constr * pat * substitution option and substitution = (int * constr) list -type problem = rel_context * identifier * pat list - -(* let vars_of_tele = map (fun (id, _, _) -> mkVar id) *) +type problem = identifier * lhs let rels_of_tele tele = rel_list 0 (List.length tele) let patvars_of_tele tele = map (fun c -> PRel (destRel c)) (rels_of_tele tele) -let split_solves split (delta, id, pats) = +let split_solves split prob = match split with - | Compute (ctx, lhs, rhs) -> delta = ctx && pats = lhs - | Split (ctx, lhs, id, indf, us, ls) -> delta = ctx && pats = lhs + | Compute (lhs, rhs) -> lhs = prob + | Split (lhs, id, indf, us, ls) -> lhs = prob let ids_of_constr c = let rec aux vars c = @@ -244,21 +267,26 @@ let split_tele n ctx = | _ -> raise (Invalid_argument "split_tele") in aux [] n ctx -let add_var_subst subst n c = - if mem_assoc n subst then - if eq_constr (assoc n subst) c then subst - else raise Conflict - else (n, c) :: subst +let rec add_var_subst env subst n c = + if mem_assoc n subst then + let t = assoc n subst in + if eq_constr t c then subst + else unify env subst t c + else + let rel = mkRel n in + if rel = c then subst + else if dependent rel c then raise Conflict + else (n, c) :: subst -let rec unify env subst x y = +and unify env subst x y = match kind_of_term x, kind_of_term y with - | Rel n, _ -> add_var_subst subst n y - | _, Rel n -> add_var_subst subst n x + | Rel n, _ -> add_var_subst env subst n y + | _, Rel n -> add_var_subst env subst n x | App (c, l), App (c', l') when eq_constr c c' -> unify_constrs env subst (Array.to_list l) (Array.to_list l') | _, _ -> if eq_constr x y then subst else raise Conflict -and unify_constrs env subst l l' = +and unify_constrs (env : env) subst l l' = if List.length l = List.length l' then fold_left2 (unify env) subst l l' else raise Conflict @@ -266,7 +294,7 @@ and unify_constrs env subst l l' = let substituted_context subst ctx = let substitute_in_ctx n c ctx = let rec aux k after = function - | [] -> assert false + | [] -> [] | decl :: before -> if k = n then subst_rel_context 0 c (rev after) @ before else aux (succ k) (decl :: after) before @@ -292,7 +320,7 @@ let substituted_context subst ctx = let t' = lift (-k) t in (* caution, not always well defined *) let ctx' = substitute_in_ctx k t' ctx' in let rest' = substitute_in_subst k t' rest in - record_subst (pred k) (lift (-1) t); + record_subst (pred k) (liftn (-1) k t); aux ctx' rest' in let ctx' = aux ctx subst in @@ -304,65 +332,79 @@ let unify_type before ty = let envb = push_rel_context before (Global.env()) in let IndType (indf, args) = find_rectype envb Evd.empty ty in let ind, params = dest_ind_family indf in -(* let vs = params @ args in *) - let vs = args in + let vs = map (Reduction.whd_betadeltaiota envb) args in let cstrs = Inductiveops.arities_of_constructors envb ind in let cstrs = Array.mapi (fun i ty -> let ty = prod_applist ty params in let ctx, ty = decompose_prod_assum ty in + let ctx, ids = + let ids = ids_of_rel_context ctx in + fold_right (fun (n, b, t as decl) (acc, ids) -> + match n with Name _ -> (decl :: acc), ids + | Anonymous -> let id = next_name_away Anonymous ids in + ((Name id, b, t) :: acc), (id :: ids)) + ctx ([], ids) + in let env' = push_rel_context ctx (Global.env ()) in let IndType (indf, args) = find_rectype env' Evd.empty ty in let ind, params = dest_ind_family indf in let constr = applist (mkConstruct (ind, succ i), params @ rels_of_tele ctx) in - let constrpat = PCstr ((ind, succ i), innacs_of_constrs params @ patvars_of_tele ctx) in + let constrpat = PCstr ((ind, succ i), inaccs_of_constrs params @ patvars_of_tele ctx) in env', ctx, constr, constrpat, (* params @ *)args) cstrs in + let res = Array.map (fun (env', ctxc, c, cpat, us) -> - let beforelen = length before and ctxclen = length ctxc in - let fullctx = (* lift_contextn beforelen 1 *)ctxc @ before in -(* let c = liftn beforelen (succ ctxclen) c and cpat = lift_pat beforelen ctxclen cpat in *) + let _beforelen = length before and ctxclen = length ctxc in + let fullctx = ctxc @ before in try let fullenv = push_rel_context fullctx (Global.env ()) in - let vs' = map (lift ctxclen) vs - and us' = map (liftn beforelen (succ ctxclen)) us in - let subst = unify_constrs fullenv [] us' vs' in + let vs' = map (lift ctxclen) vs in + let subst = unify_constrs fullenv [] us vs' in let subst', ctx' = substituted_context subst fullctx in - (ctx', ctxc, c, cpat, Some subst') + (ctx', ctxclen, c, cpat, Some subst') with Conflict -> - (fullctx, ctxc, c, cpat, None)) cstrs, indf + (fullctx, ctxclen, c, cpat, None)) cstrs + in Some (res, indf) with Not_found -> (* not an inductive type *) - raise (Invalid_argument "unify_type: Not an inductive type") + None let rec id_of_rel n l = match n, l with | 0, (Name id, _, _) :: tl -> id | n, _ :: tl -> id_of_rel (pred n) tl | _, _ -> raise (Invalid_argument "id_of_rel") + +let constrs_of_lhs ?(inacc=true) env (ctx, _, pats) = + constrs_of_pats ~inacc (push_rel_context ctx env) pats let rec valid_splitting (f, delta, t, pats) tree = split_solves tree (delta, f, pats) && valid_splitting_tree (f, delta, t) tree and valid_splitting_tree (f, delta, t) = function - | Compute (ctx, lhs, Program rhs) -> - let subst = constrs_of_pats lhs in - ignore(check_judgment ctx rhs (substl subst t)); true + | Compute (lhs, Program rhs) -> + let subst = constrs_of_lhs ~inacc:false (Global.env ()) lhs in + ignore(check_judgment (pi1 lhs) rhs (substl subst t)); true - | Compute (ctx, lhs, Empty split) -> + | Compute ((ctx, id, lhs), Empty split) -> let before, (x, _, ty), after = split_context split ctx in - let unify, _ = unify_type before ty in + let unify = + match unify_type before ty with + | Some (unify, _) -> unify + | None -> assert false + in array_for_all (fun (_, _, _, _, x) -> x = None) unify - | Split (ctx, lhs, rel, indf, unifs, ls) -> + | Split ((ctx, id, lhs), rel, indf, unifs, ls) -> let before, (id, _, ty), after = split_tele (pred rel) ctx in - let unify, indf' = unify_type before ty in + let unify, indf' = Option.get (unify_type before ty) in assert(indf = indf'); if not (array_exists (fun (_, _, _, _, x) -> x <> None) unify) then false else let ok, splits = - Array.fold_left (fun (ok, splits as acc) (ctx', ctxc, cstr, cstrpat, subst) -> + Array.fold_left (fun (ok, splits as acc) (ctx', ctxlen, cstr, cstrpat, subst) -> match subst with | None -> acc | Some subst -> @@ -374,13 +416,15 @@ and valid_splitting_tree (f, delta, t) = function (* in *) let newdelta = subst_context subst (subst_rel_context 0 cstr - (lift_contextn (length ctxc) 0 after)) @ before in - let liftpats = lift_pats (length ctxc) rel lhs in - let newpats = specialize_pats subst (subst_pats rel cstrpat liftpats) in + (lift_contextn ctxlen 0 after)) @ before in + let liftpats = lift_pats ctxlen rel lhs in + let newpats = specialize_pats subst (subst_pats (Global.env ()) rel cstrpat liftpats) in (ok, (f, newdelta, newpats) :: splits)) (true, []) unify in - let subst = List.map2 (fun (id, _, _) x -> out_name id, x) delta (constrs_of_pats lhs) in + let subst = List.map2 (fun (id, _, _) x -> out_name id, x) delta + (constrs_of_pats ~inacc:false (Global.env ()) lhs) + in let t' = replace_vars subst t in ok && for_all (fun (f, delta', pats') -> @@ -389,23 +433,17 @@ and valid_splitting_tree (f, delta, t) = function let valid_tree (f, delta, t) tree = valid_splitting (f, delta, t, patvars_of_tele delta) tree -let find_split curpats patcs = +let find_split (_, _, curpats : lhs) (_, _, patcs : lhs) = let rec find_split_pat curpat patc = - match kind_of_term patc with - | Rel _ -> (* The pattern's a variable, don't split *) None - | App (f, args) when isConstruct f -> - let f = destConstruct f in - (match curpat with - | PCstr (f', args') when f = f' -> (* Already split at this level, continue *) - find_split_pats args' (Array.to_list args) - | PRel i -> (* Split on i *) Some i - | _ -> None) - | Construct f -> + match patc with + | PRel _ -> (* The pattern's a variable, don't split *) None + | PCstr (f, args) -> (match curpat with - | PCstr (f', []) when f = f' -> (* Already split at this level, no args *) None + | PCstr (f', args') when f = f' -> (* Already split at this level, continue *) + find_split_pats args' args | PRel i -> (* Split on i *) Some i | _ -> None) - | _ -> None + | PInac _ -> None and find_split_pats curpats patcs = assert(List.length curpats = List.length patcs); @@ -424,45 +462,81 @@ let pr_constr_pat env c = | App _ -> str "(" ++ pr ++ str ")" | _ -> pr -let pr_clause env (delta, patcs, rhs) = +let pr_pat env c = + try + let patc = constr_of_pat env c in + try pr_constr_pat env patc with _ -> str"pr_constr_pat raised an exception" + with _ -> str"constr_of_pat raised an exception" + +let pr_context env c = + let pr_decl (id,b,_) = match id with Name id -> pr_id id | Anonymous -> str"_" in + prlist_with_sep pr_spc pr_decl (List.rev c) +(* Printer.pr_rel_context env c *) + +let pr_lhs env (delta, f, patcs) = let env = push_rel_context delta env in - prlist_with_sep spc (pr_constr_pat env) patcs + let ctx = pr_context env delta in + (if delta = [] then ctx else str "[" ++ ctx ++ str "]" ++ spc ()) + ++ pr_id f ++ spc () ++ prlist_with_sep spc (pr_pat env) patcs + +let pr_rhs env = function + | Empty var -> spc () ++ str ":=!" ++ spc () ++ print_constr_env env (mkRel var) + | Program rhs -> spc () ++ str ":=" ++ spc () ++ print_constr_env env rhs + +let pr_clause env (lhs, rhs) = + pr_lhs env lhs ++ + (let env' = push_rel_context (pi1 lhs) env in + pr_rhs env' rhs) + +(* let pr_splitting env = function *) +(* | Compute cl -> str "Compute " ++ pr_clause env cl *) +(* | Split (lhs, n, indf, results, splits) -> *) + +(* let pr_unification_result (ctx, n, c, pat, subst) = *) + +(* unification_result array * splitting option array *) let pr_clauses env = prlist_with_sep fnl (pr_clause env) + + +let lhs_matches (delta, _, patcs : lhs) (delta', _, patcs' : lhs) = + pattern_matches patcs patcs' -let rec split_on env fdt var delta curpats clauses = +let rec split_on env var (delta, f, curpats as lhs) clauses = let before, (id, _, ty), after = split_tele (pred var) delta in - let unify, indf = unify_type before ty in + let unify, indf = + match unify_type before ty with + | Some r -> r + | None -> assert false (* We decided... so it better be inductive *) + in let clauses = ref clauses in let splits = - Array.map (fun (ctx', ctxc, cstr, cstrpat, s) -> + Array.map (fun (ctx', ctxlen, cstr, cstrpat, s) -> match s with | None -> None | Some s -> (* ctx' |- s cstr, s cstrpat *) let newdelta = subst_context s (subst_rel_context 0 cstr - (lift_contextn (length ctxc) 1 after)) @ ctx' in + (lift_contextn ctxlen 1 after)) @ ctx' in let liftpats = (* delta |- curpats -> before; ctxc; id; after |- liftpats *) - lift_pats (length ctxc) (succ var) curpats + lift_pats ctxlen (succ var) curpats in let liftpat = (* before; ctxc |- cstrpat -> before; ctxc; after |- liftpat *) lift_pat (pred var) 1 cstrpat in let substpat = (* before; ctxc; after |- liftpats[id:=liftpat] *) - subst_pats var liftpat liftpats + subst_pats env var liftpat liftpats in let lifts = (* before; ctxc |- s : newdelta -> before; ctxc; after |- lifts : newdelta ; after *) map (fun (k,x) -> (pred var + k, lift (pred var) x)) s in let newpats = specialize_pats lifts substpat in - let matching, rest = partition (fun (delta', patcs, rhs) -> - try ignore(pattern_matches newpats patcs); true with Conflict -> false) - !clauses - in + let newlhs = (newdelta, f, newpats) in + let matching, rest = partition (fun (lhs, rhs) -> lhs_matches newlhs lhs) !clauses in clauses := rest; if matching = [] then ( (* Try finding a splittable variable *) @@ -471,43 +545,61 @@ let rec split_on env fdt var delta curpats clauses = match accid with | Some _ -> (accid, ctx) | None -> - let unify, indf = unify_type ctx ty in - if array_for_all (fun (_, _, _, _, x) -> x = None) unify then - (Some id, ctx) - else (None, decl :: ctx)) + match unify_type ctx ty with + | Some (unify, indf) -> + if array_for_all (fun (_, _, _, _, x) -> x = None) unify then + (Some id, ctx) + else (None, decl :: ctx) + | None -> (None, decl :: ctx)) newdelta (None, []) in match id with | None -> errorlabstrm "deppat" (str "Non-exhaustive pattern-matching, no clause found for:" ++ fnl () ++ - pr_clause env (newdelta, constrs_of_pats newpats, Empty var)) + pr_lhs env newlhs) | Some id -> - Some (Compute (newdelta, newpats, - Empty (fst (lookup_rel_id (out_name id) newdelta)))) + Some (Compute (newlhs, Empty (fst (lookup_rel_id (out_name id) newdelta)))) ) else ( - let splitting = make_split_aux env fdt newdelta newpats matching in + let splitting = make_split_aux env newlhs matching in Some splitting)) unify in - assert(!clauses = []); - Split (delta, curpats, var, indf, unify, splits) + if !clauses <> [] then + errorlabstrm "deppat" + (str "Impossible clauses:" ++ fnl () ++ pr_clauses env !clauses); + Split (lhs, var, indf, unify, splits) -and make_split_aux env (f, d, t as fdt) delta curpats clauses = - match clauses with - (delta', patcs, rhs) :: clauses' -> - (match find_split curpats patcs with - | None -> (* No need to split anymore *) - let res = Compute (delta', pats_of_constrs patcs, rhs) in - if clauses' <> [] then +and make_split_aux env lhs clauses = + let split = + fold_left (fun acc (lhs', rhs) -> + match acc with + | None -> find_split lhs lhs' + | _ -> acc) None clauses + in + match split with + | Some var -> split_on env var lhs clauses + | None -> + (match clauses with + | [] -> error "No clauses left" + | [(lhs, rhs)] -> + (* No need to split anymore *) + Compute (lhs, rhs) +(* (match rhs with *) +(* | Program _ -> *) +(* Compute (delta', pats_of_constrs patcs, rhs) *) +(* | Empty split -> (\* TODO : Check unify_type inductive type *\) *) +(* Compute (delta', pats_of_constrs patcs, rhs) *) + (* errorlabstrm "deppat" *) + (* (str "Splitting on " ++ pr_id x ++ str " of type " ++ *) + (* pr_constr_env (push_rel_context before env) *) + (* an empty type, on variable)) *) + | _ -> errorlabstrm "make_split_aux" - (str "Overlapping clauses:" ++ fnl () ++ pr_clauses env clauses) - else res - | Some var -> split_on env fdt var delta curpats clauses) - | [] -> error "No clauses left" + (str "Overlapping clauses:" ++ fnl () ++ pr_clauses env clauses)) let make_split env (f, delta, t) clauses = - make_split_aux env (f, delta, t) delta (patvars_of_tele delta) clauses + make_split_aux env (delta, f, patvars_of_tele delta) clauses open Evd open Evarutil @@ -515,29 +607,29 @@ open Evarutil let lift_substitution n s = map (fun (k, x) -> (k + n, x)) s let map_substitution s t = map (subst_rel_subst 0 s) t -let term_of_tree isevar env (i, delta, ty) tree = +let term_of_tree status isevar env (i, delta, ty) tree = let rec aux = function - | Compute (ctx, lhs, Program rhs) -> - let ty' = substl (rev (constrs_of_pats lhs)) ty in + | Compute ((ctx, _, pats as lhs), Program rhs) -> + let ty' = substl (rev (constrs_of_lhs ~inacc:false env lhs)) ty in let body = it_mkLambda_or_LetIn rhs ctx and typ = it_mkProd_or_LetIn ty' ctx in mkCast(body, DEFAULTcast, typ), typ - | Compute (ctx, lhs, Empty split) -> - let ty' = substl (rev (constrs_of_pats lhs)) ty in + | Compute ((ctx, _, pats as lhs), Empty split) -> + let ty' = substl (rev (constrs_of_lhs ~inacc:false env lhs)) ty in let split = (Name (id_of_string "split"), Some (Class_tactics.coq_nat_of_int (1 + (length ctx - split))), Lazy.force Class_tactics.coq_nat) in let ty' = it_mkProd_or_LetIn ty' ctx in let let_ty' = mkLambda_or_LetIn split (lift 1 ty') in - let term = e_new_evar isevar env ~src:(dummy_loc, QuestionMark true) let_ty' in + let term = e_new_evar isevar env ~src:(dummy_loc, QuestionMark (Define true)) let_ty' in term, ty' - | Split (ctx, lhs, rel, indf, unif, sp) -> + | Split ((ctx, _, pats as lhs), rel, indf, unif, sp) -> let before, decl, after = split_tele (pred rel) ctx in - let ty' = substl (rev (constrs_of_pats lhs)) ty in + let ty' = substl (rev (constrs_of_lhs ~inacc:false env lhs)) ty in let branches = - array_map2 (fun (ctx', ctxc, cstr, cstrpat, subst) split -> + array_map2 (fun (ctx', ctxlen, cstr, cstrpat, subst) split -> match split with | Some s -> aux s | None -> @@ -567,7 +659,7 @@ let term_of_tree isevar env (i, delta, ty) tree = Lazy.force Class_tactics.coq_nat) in let ty = it_mkLambda_or_LetIn (lift 2 ty) [nbbranches;nbdiscr] in - let term = e_new_evar isevar env ~src:(dummy_loc, QuestionMark true) ty in + let term = e_new_evar isevar env ~src:(dummy_loc, QuestionMark status) ty in term in let casetyp = it_mkProd_or_LetIn ty' ctx in @@ -644,10 +736,26 @@ let interp_eqn i isevar env impls sign arity recu (pats, rhs) = | Program p -> Program (interp_casted_constr_evars isevar env' ~impls p (substl patcs arity)) | Empty lid -> Empty (fst (lookup_rel_id (snd lid) ctx)) - in (ctx, rev patcs, rhs') + in ((ctx, i, pats_of_constrs (rev patcs)), rhs') open Entries +open Tacmach +open Tacexpr +open Tactics +open Tacticals + +let contrib_tactics_path = + make_dirpath (List.map id_of_string ["Equality";"Program";"Coq"]) + +let tactics_tac s = + make_kn (MPfile contrib_tactics_path) (make_dirpath []) (mk_label s) + +let equations_tac = lazy + (Tacinterp.eval_tactic + (TacArg(TacCall(dummy_loc, + ArgArg(dummy_loc, tactics_tac "equations"), [])))) + let define_by_eqs i l t nt eqs = let env = Global.env () in let isevar = ref (create_evar_defs Evd.empty) in @@ -655,7 +763,8 @@ let define_by_eqs i l t nt eqs = let arity = interp_type_evars isevar env' t in let ty = it_mkProd_or_LetIn arity sign in let data = Command.compute_interning_datas env [] [i] [ty] [impls] in - let fixenv = push_rel (Name i, None, ty) env in + let fixdecls = [(Name i, None, ty)] in + let fixenv = push_rel_context fixdecls env in let equations = States.with_heavy_rollback (fun () -> Option.iter (Command.declare_interning_data data) nt; @@ -665,10 +774,11 @@ let define_by_eqs i l t nt eqs = let arity = nf_evar (Evd.evars_of !isevar) arity in let prob = (i, sign, arity) in let fixenv = nf_env_evar (Evd.evars_of !isevar) fixenv in - let ce = check_evars fixenv Evd.empty !isevar in - List.iter (function (_, _, Program rhs) -> ce rhs | _ -> ()) equations; + let fixdecls = nf_rel_context_evar (Evd.evars_of !isevar) fixdecls in + (* let ce = check_evars fixenv Evd.empty !isevar in *) + (* List.iter (function (_, _, Program rhs) -> ce rhs | _ -> ()) equations; *) let is_recursive, env' = - let occur_eqn (ctx, _, rhs) = + let occur_eqn ((ctx, _, _), rhs) = match rhs with | Program c -> dependent (mkRel (succ (length ctx))) c | _ -> false @@ -676,19 +786,23 @@ let define_by_eqs i l t nt eqs = in let split = make_split env' prob equations in (* if valid_tree prob split then *) - let t, ty = term_of_tree isevar env' prob split in - let t = - if is_recursive then - let firstsplit = - match split with - | Split (ctx, lhs, rel, indf, unif, sp) -> (length ctx - rel) - | _ -> 0 - in mkFix (([|firstsplit|], 0), ([|Name i|], [|ty|], [|t|])) - else t - in + let status = (* if is_recursive then Expand else *) Define false in + let t, ty = term_of_tree status isevar env' prob split in let undef = undefined_evars !isevar in - let obls, t', ty' = Eterm.eterm_obligations env i !isevar (Evd.evars_of undef) 0 t ty in - ignore(Subtac_obligations.add_definition ~implicits:impls i t' ty' obls) + let t, ty = if is_recursive then + (it_mkLambda_or_LetIn t fixdecls, it_mkProd_or_LetIn ty fixdecls) + else t, ty + in + let obls, t', ty' = + Eterm.eterm_obligations env i !isevar (Evd.evars_of undef) 0 ~status t ty + in + if is_recursive then + ignore(Subtac_obligations.add_mutual_definitions [(i, t', ty', impls, obls)] [] + ~tactic:(Lazy.force equations_tac) + (Command.IsFixpoint [None, CStructRec])) + else + ignore(Subtac_obligations.add_definition + ~implicits:impls i t' ty' ~tactic:(Lazy.force equations_tac) obls) module Gram = Pcoq.Gram module Vernac = Pcoq.Vernac_ @@ -765,28 +879,13 @@ VERNAC COMMAND EXTEND Define_equations decl_notation(nt) ] -> [ define_by_eqs i l t nt eqs ] END - -open Tacmach -open Tacexpr -open Tactics -open Tacticals - -let contrib_tactics_path = - make_dirpath (List.map id_of_string ["Equality";"Program";"Coq"]) - -let tactics_tac s = - lazy(make_kn (MPfile contrib_tactics_path) (make_dirpath []) (mk_label s)) - -let destruct_last args = - Tacinterp.eval_tactic (TacArg(TacCall(dummy_loc, - ArgArg(dummy_loc, Lazy.force (tactics_tac "destruct_last")),args))) let rec int_of_coq_nat c = match kind_of_term c with | App (f, [| arg |]) -> succ (int_of_coq_nat arg) | _ -> 0 -let solve_equations_goal tac gl = +let solve_equations_goal destruct_tac tac gl = let concl = pf_concl gl in let targetn, branchesn, targ, brs, b = match kind_of_term concl with @@ -811,10 +910,10 @@ let solve_equations_goal tac gl = let cleantac = tclTHEN (intros_using ids) (thin ids) in let dotac = tclDO (succ targ) intro in let subtacs = - tclTHENS (destruct_last []) + tclTHENS destruct_tac (map (fun (id, br, brt) -> tclTHEN (letin_tac None (Name id) br onConcl) tac) branches) in tclTHENLIST [cleantac ; dotac ; subtacs] gl - + TACTIC EXTEND solve_equations - [ "solve_equations" tactic(tac) ] -> [ solve_equations_goal (snd tac) ] + [ "solve_equations" tactic(destruct) tactic(tac) ] -> [ solve_equations_goal (snd destruct) (snd tac) ] END diff --git a/proofs/logic.ml b/proofs/logic.ml index 818a32cea..c07b6a800 100644 --- a/proofs/logic.ml +++ b/proofs/logic.ml @@ -57,6 +57,8 @@ let rec catchable_exception = function |NoOccurrenceFound _|CannotUnifyBindingType _|NotClean _ |CannotFindWellTypedAbstraction _ |UnsolvableImplicit _)) -> true + | Typeclasses_errors.TypeClassError + (_, Typeclasses_errors.UnsatisfiableConstraints _) -> true | _ -> false (* Tells if the refiner should check that the submitted rules do not diff --git a/test-suite/success/Equations.v b/test-suite/success/Equations.v index ea4d693dd..160940185 100644 --- a/test-suite/success/Equations.v +++ b/test-suite/success/Equations.v @@ -1,8 +1,6 @@ Require Import Bvector. Require Import Program. -Obligation Tactic := try equations. - Equations neg (b : bool) : bool := neg true := false ; neg false := true. @@ -27,17 +25,16 @@ Eval compute in (tail (cons 1 nil)). Reserved Notation " x ++ y " (at level 60, right associativity). +Equations app' {A} (l l' : list A) : (list A) := +app' A nil l := l ; +app' A (cons a v) l := cons a (app' v l). + Equations app (l l' : list nat) : list nat := [] ++ l := l ; (a :: v) ++ l := a :: (v ++ l) where " x ++ y " := (app x y). -Equations app' {A} (l l' : list A) : (list A) := -app' A nil l := l ; -app' A (cons a v) l := cons a (app' v l). - - Eval compute in @app'. Equations zip' {A} (f : A -> A -> A) (l l' : list A) : (list A) := @@ -46,9 +43,8 @@ zip' A f (cons a v) (cons b w) := cons (f a b) (zip' f v w) ; zip' A f nil (cons b w) := nil ; zip' A f (cons a v) nil := nil. -Eval compute in @zip'. -Eval cbv delta [ zip' zip'_obligation_1 zip'_obligation_2 zip'_obligation_3 ] beta iota zeta in @zip'. +Eval compute in @zip'. Equations zip'' {A} (f : A -> A -> A) (l l' : list A) (def : list A) : (list A) := zip'' A f nil nil def := nil ; @@ -57,7 +53,6 @@ zip'' A f nil (cons b w) def := def ; zip'' A f (cons a v) nil def := def. Eval compute in @zip''. -Eval cbv delta [ zip'' ] beta iota zeta in @zip''. Implicit Arguments Vnil [[A]]. Implicit Arguments Vcons [[A] [n]]. @@ -105,8 +100,6 @@ Section Image. Equations inv (t : T) (im : Imf t) : S := inv (f s) (imf s) := s. - Eval compute in inv. - End Image. Section Univ. @@ -131,3 +124,91 @@ End Univ. Eval compute in (foo ubool false). Eval compute in (foo (uarrow ubool ubool) negb). Eval compute in (foo (uarrow ubool ubool) id). + +(* Overlap. *) + +Inductive foobar : Set := bar | baz. + +Equations bla f : bool := +bla bar := true ; +bla baz := false. + +Eval simpl in bla. +Print refl_equal. + +Notation "'refl'" := (@refl_equal _ _). + +Equations K {A} (x : A) (P : x = x -> Type) (p : P (refl_equal x)) (p : x = x) : P p := +K A x P p refl := p. + +Equations eq_sym {A} (x y : A) (H : x = y) : y = x := +eq_sym A x x refl := refl. + +(* Obligation Tactic := idtac. *) + +Equations eq_trans {A} (x y z : A) (p : x = y) (q : y = z) : x = z := +eq_trans A x x x refl refl := refl. + +Lemma eq_trans_eq A x : @eq_trans A x x x refl refl = refl. +Proof. reflexivity. Qed. + +Equations nth {A} {n} (v : vector A n) (f : fin n) : A := +nth A (S n) (Vcons a v) fz := a ; +nth A (S n) (Vcons a v) (fs f) := nth v f. + +Equations tabulate {A} {n} (f : fin n -> A) : vector A n := +tabulate A 0 f := Vnil ; +tabulate A (S n) f := Vcons (f fz) (tabulate (f ∘ fs)). + +Equations vlast {A} {n} (v : vector A (S n)) : A := +vlast A 0 (Vcons a Vnil) := a ; +vlast A (S n) (Vcons a v) := vlast v. + +Lemma vlast_equation1 A (a : A) : vlast (Vcons a Vnil) = a. +Proof. intros. compute ; reflexivity. Qed. + +Lemma vlast_equation2 A n a v : @vlast A (S n) (Vcons a v) = vlast v. +Proof. intros. compute ; reflexivity. Qed. + +Print Assumptions vlast. +Print Assumptions nth. +Print Assumptions tabulate. + +Equations vliat {A} {n} (v : vector A (S n)) : vector A n := +vliat A 0 (Vcons a Vnil) := Vnil ; +vliat A (S n) (Vcons a v) := Vcons a (vliat v). + +Eval compute in (vliat (Vcons 2 (Vcons 5 (Vcons 4 Vnil)))). + +Equations vapp {A} {n m} (v : vector A n) (w : vector A m) : vector A (n + m) := +vapp A 0 m Vnil w := w ; +vapp A (S n) m (Vcons a v) w := Vcons a (vapp v w). + +Lemma JMeq_Vcons_inj A n m a (x : vector A n) (y : vector A m) : n = m -> JMeq x y -> JMeq (Vcons a x) (Vcons a y). +Proof. intros until y. simplify_dep_elim. reflexivity. Qed. + +Equations NoConfusion_fin (P : Prop) {n : nat} (x y : fin n) : Prop := +NoConfusion_fin P (S n) fz fz := P -> P ; +NoConfusion_fin P (S n) fz (fs y) := P ; +NoConfusion_fin P (S n) (fs x) fz := P ; +NoConfusion_fin P (S n) (fs x) (fs y) := (x = y -> P) -> P. + +Equations noConfusion_fin P (n : nat) (x y : fin n) (H : x = y) : NoConfusion_fin P x y := +noConfusion_fin P (S n) fz fz refl := λ p, p ; +noConfusion_fin P (S n) (fs x) (fs x) refl := λ p : x = x -> P, p refl. + +Equations NoConfusion_vect (P : Prop) {A n} (x y : vector A n) : Prop := +NoConfusion_vect P A 0 Vnil Vnil := P -> P ; +NoConfusion_vect P A (S n) (Vcons a x) (Vcons b y) := (a = b -> x = y -> P) -> P. + +Equations noConfusion_vect (P : Prop) A n (x y : vector A n) (H : x = y) : NoConfusion_vect P x y := +noConfusion_vect P A 0 Vnil Vnil refl := λ p, p ; +noConfusion_vect P A (S n) (Vcons a v) (Vcons a v) refl := λ p : a = a -> v = v -> P, p refl refl. + +Instance fin_noconf n : NoConfusionPackage (fin n) := + NoConfusion := λ P, Π x y, x = y -> NoConfusion_fin P x y ; + noConfusion := λ P x y, noConfusion_fin P n x y. + +Instance vect_noconf A n : NoConfusionPackage (vector A n) := + NoConfusion := λ P, Π x y, x = y -> NoConfusion_vect P x y ; + noConfusion := λ P x y, noConfusion_vect P A n x y. diff --git a/theories/Program/Equality.v b/theories/Program/Equality.v index d11996a67..3e0e8ca2b 100644 --- a/theories/Program/Equality.v +++ b/theories/Program/Equality.v @@ -1,3 +1,4 @@ +(* -*- coq-prog-name: "~/research/coq/trunk/bin/coqtop.byte"; coq-prog-args: ("-emacs-U" "-top" "Coq.Program.Equality"); compile-command: "make -C ../.. TIME='time'" -*- *) (************************************************************************) (* v * The Coq Proof Assistant / The Coq Development Team *) (* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *) @@ -19,6 +20,10 @@ Require Import Coq.Program.Tactics. Notation " [ x : X ] = [ y : Y ] " := (@JMeq X x Y y) (at level 0, X at next level, Y at next level). +(** Notation for the single element of [x = x] *) + +Notation "'refl'" := (@refl_equal _ _). + (** Do something on an heterogeneous equality appearing in the context. *) Ltac on_JMeq tac := @@ -309,17 +314,15 @@ Tactic Notation "dependent" "induction" ident(H) "generalizing" ne_hyp_list(l) " These tactics implement the necessary machinery to solve goals produced by the [Equations] command relative to dependent pattern-matching. It is completely inspired from the "Eliminating Dependent Pattern-Matching" paper by - Goguen, McBride and McKinna. - -*) + Goguen, McBride and McKinna. *) (** Lemmas used by the simplifier, mainly rephrasings of [eq_rect], [eq_ind]. *) Lemma solution_left : Π A (B : A -> Type) (t : A), B t -> (Π x, x = t -> B x). -Proof. intros; subst; assumption. Defined. +Proof. intros; subst. apply X. Defined. Lemma solution_right : Π A (B : A -> Type) (t : A), B t -> (Π x, t = x -> B x). -Proof. intros; subst; assumption. Defined. +Proof. intros; subst; apply X. Defined. Lemma deletion : Π A B (t : A), B -> (t = t -> B). Proof. intros; assumption. Defined. @@ -331,6 +334,21 @@ Lemma simplification_existT : Π A (P : A -> Type) B (p : A) (x y : P p), (x = y -> B) -> (existT P p x = existT P p y -> B). Proof. intros. apply X. apply inj_pair2. exact H. Defined. +Lemma simplification_K : Π A (x : A) (B : x = x -> Type), B (refl_equal x) -> (Π p : x = x, B p). +Proof. intros. rewrite (UIP_refl A). assumption. Defined. + +(** The NoConfusionPackage class provides a method for making progress on proving a property + [P] implied by an equality on an inductive type [I]. The type of [noConfusion] for a given + [P] should be of the form [ Π Δ, (x y : I Δ) (x = y) -> NoConfusion P x y ], where + [NoConfusion P x y] for constructor-headed [x] and [y] will give a formula ending in [P]. + This gives a general method for simplifying by discrimination or injectivity of constructors. + + Some actual instances are defined later in the file using the more primitive [discriminate] and + [injection] tactics on which we can always fall back. + *) + +Class NoConfusionPackage (I : Type) := NoConfusion : Π P : Prop, Type ; noConfusion : Π P, NoConfusion P. + (** This hint database and the following tactic can be used with [autosimpl] to unfold everything to [eq_rect]s. *) @@ -354,18 +372,20 @@ Ltac simplify_equations := repeat (unfold_equations ; simplify_eqs). Ltac simplify_one_dep_elim_term c := match c with | @JMeq ?A ?a ?A ?b -> _ => refine (simplification_heq _ _ _ _ _) - | ?t = ?t -> _ => intros _ + | ?t = ?t -> _ => intros _ || refine (simplification_K _ t _ _) | eq (existT ?P ?p _) (existT ?P ?p _) -> _ => refine (simplification_existT _ _ _ _ _ _ _) - | ?f ?x = ?f ?y -> _ => let H := fresh in intros H ; injection H ; clear H | ?x = ?y -> _ => - (let hyp := fresh in intros hyp ; - move dependent hyp before x ; + (let hyp := fresh in intros hyp ; + move dependent hyp before x ; generalize dependent x ; refine (solution_left _ _ _ _) ; intros until 0) || - (let hyp := fresh in intros hyp ; - move dependent hyp before y ; + (let hyp := fresh in intros hyp ; + move dependent hyp before y ; generalize dependent y ; refine (solution_right _ _ _ _) ; intros until 0) + | @eq ?A ?t ?u -> ?P => apply (noConfusion (I:=A) P) + | ?f ?x = ?g ?y -> _ => let H := fresh in intros H ; injection H ; clear H | ?t = ?u -> _ => let hyp := fresh in intros hyp ; elimtype False ; discriminate + | id ?T => fail 1 (* Do not put any part of the rhs in the hyps *) | _ => intro end. @@ -392,32 +412,59 @@ Ltac destruct_last := (** The rest is support tactics for the [Equations] command. *) +(** Notation for inaccessible patterns. *) + +Definition inaccessible_pattern {A : Type} (t : A) := t. + +Notation "?( t )" := (inaccessible_pattern t). + +(** To handle sections, we need to separate the context in two parts: + variables introduced by the section and the rest. We introduce a dummy variable + between them to indicate that. *) + +CoInductive end_of_section := the_end_of_the_section. + +Ltac set_eos := let eos := fresh "eos" in + assert (eos:=the_end_of_the_section). + +(** We have a specialized [reverse_local] tactic to reverse the goal until the begining of the + section variables *) + +Ltac reverse_local := + match goal with + | [ H : ?T |- _ ] => + match T with + | end_of_section => idtac | _ => revert H ; reverse_local end + | _ => idtac + end. + (** Do as much as possible to apply a method, trying to get the arguments right. *) -Ltac try_intros m := - (eapply m ; eauto) || (intro ; try_intros m). +Ltac simpl_apply m := refine m. (* || apply m || simpl ; apply m. *) + +Ltac try_intros m := unfold Datatypes.id ; refine m || apply m. (* (repeat simpl_apply m || intro). *) (** To solve a goal by inversion on a particular target. *) Ltac solve_empty target := do_nat target intro ; elimtype False ; destruct_last ; simplify_dep_elim. -Ltac simplify_method H := clear H ; simplify_dep_elim ; reverse. +Ltac simplify_method tac := repeat (tac || simplify_one_dep_elim) ; reverse_local. -(** Solving a method call: we must refine the goal until the body - can be applied or just solve it by splitting on an empty family member. *) +(** Solving a method call: we can solve it by splitting on an empty family member + or we must refine the goal until the body can be applied. *) Ltac solve_method rec := match goal with - | [ H := ?body : nat |- _ ] => simplify_method H ; solve_empty body - | [ H := ?body |- _ ] => simplify_method H ; rec ; try_intros body + | [ H := ?body : nat |- _ ] => subst H ; clear ; abstract (simplify_method idtac ; solve_empty body) + | [ H := ?body |- _ ] => clear H ; simplify_method ltac:(exact body) ; rec ; try_intros body end. (** Impossible cases, by splitting on a given target. *) Ltac solve_split := match goal with - | [ |- let split := ?x : nat in _ ] => intros _ ; solve_empty x + | [ |- let split := ?x : nat in _ ] => clear ; abstract (intros _ ; solve_empty x) end. (** If defining recursive functions, the prototypes come first. *) @@ -428,19 +475,98 @@ Ltac intro_prototypes := | _ => idtac end. +Ltac case_last := + match goal with + | [ p : ?x = ?x |- ?T ] => change (id T) ; revert p ; refine (simplification_K _ x _ _) + | [ p : ?x = ?y |- ?T ] => change (id T) ; revert p + | [ p : _ |- ?T ] => simpl in p ; change (id T) ; generalize_eqs p ; destruct p + end. + Ltac nonrec_equations := - solve [solve_equations (solve_method idtac)] || solve [ solve_split ] + solve [solve_equations (case_last) (solve_method idtac)] || solve [ solve_split ] || fail "Unnexpected equations goal". Ltac recursive_equations := - solve [solve_equations (solve_method ltac:intro)] || solve [ solve_split ] + solve [solve_equations (case_last) (solve_method ltac:intro)] || solve [ solve_split ] || fail "Unnexpected recursive equations goal". (** The [equations] tactic is the toplevel tactic for solving goals generated by [Equations]. *) -Ltac equations := +Ltac equations := set_eos ; match goal with | [ |- Π x : _, _ ] => intro ; recursive_equations | _ => nonrec_equations end. + +Equations NoConfusion_nat (P : Prop) (x y : nat) : Prop := +NoConfusion_nat P 0 0 := P -> P ; +NoConfusion_nat P 0 (S y) := P ; +NoConfusion_nat P (S x) 0 := P ; +NoConfusion_nat P (S x) (S y) := (x = y -> P) -> P. +Debug Off. + Solve Obligations using equations. + +Equations noConfusion_nat (P : Prop) (x y : nat) (H : x = y) : NoConfusion_nat P x y := +noConfusion_nat P 0 0 refl := λ p, p ; +noConfusion_nat P (S n) (S n) refl := λ p : n = n -> P, p refl. + + Solve Obligations using equations. + +Instance nat_noconf : NoConfusionPackage nat := + NoConfusion := λ P, Π x y, x = y -> NoConfusion_nat P x y ; + noConfusion := λ P x y, noConfusion_nat P x y. + +Equations NoConfusion_bool (P : Prop) (x y : bool) : Prop := +NoConfusion_bool P true true := P -> P ; +NoConfusion_bool P false false := P -> P ; +NoConfusion_bool P true false := P ; +NoConfusion_bool P false true := P. + + Solve Obligations using equations. + +Equations noConfusion_bool (P : Prop) (x y : bool) (H : x = y) : NoConfusion_bool P x y := +noConfusion_bool P true true refl := λ p, p ; +noConfusion_bool P false false refl := λ p, p. + + Solve Obligations using equations. + +Instance bool_noconf : NoConfusionPackage bool := + NoConfusion := λ P, Π x y, x = y -> NoConfusion_bool P x y ; + noConfusion := λ P x y, noConfusion_bool P x y. + +Equations NoConfusion_unit (P : Prop) (x y : unit) : Prop := +NoConfusion_unit P tt tt := P -> P. + + Solve Obligations using equations. + +Equations noConfusion_unit (P : Prop) (x y : unit) (H : x = y) : NoConfusion_unit P x y := +noConfusion_unit P tt tt refl := λ p, p. + + Solve Obligations using equations. + +Instance unit_noconf : NoConfusionPackage unit := + NoConfusion := λ P, Π x y, x = y -> NoConfusion_unit P x y ; + noConfusion := λ P x y, noConfusion_unit P x y. + +Require Import List. + +Implicit Arguments nil [[A]]. + +Equations NoConfusion_list (P : Prop) (A : Type) (x y : list A) : Prop := +NoConfusion_list P A nil nil := P -> P ; +NoConfusion_list P A nil (cons a y) := P ; +NoConfusion_list P A (cons a x) nil := P ; +NoConfusion_list P A (cons a x) (cons b y) := (a = b -> x = y -> P) -> P. + + Solve Obligations using equations. + +Equations noConfusion_list (P : Prop) A (x y : list A) (H : x = y) : NoConfusion_list P A x y := +noConfusion_list P A nil nil refl := λ p, p ; +noConfusion_list P A (cons a x) (cons a x) refl := λ p : a = a -> x = x -> P, p refl refl. + + Solve Obligations using equations. + +Instance list_noconf A : NoConfusionPackage (list A) := + NoConfusion := λ P, Π x y, x = y -> NoConfusion_list P A x y ; + noConfusion := λ P x y, noConfusion_list P A x y. diff --git a/theories/Program/Tactics.v b/theories/Program/Tactics.v index 7fe5211af..9cb7725c0 100644 --- a/theories/Program/Tactics.v +++ b/theories/Program/Tactics.v @@ -121,6 +121,26 @@ Ltac on_application f tac T := | context [f ?x ?y] => tac (f x y) | context [f ?x] => tac (f x) end. + +(** A variant of [apply] using [refine], doing as much conversion as necessary. *) + +Ltac rapply p := + refine (p _ _ _ _ _ _ _ _ _ _ _ _ _ _ _) || + refine (p _ _ _ _ _ _ _ _ _ _ _ _ _ _) || + refine (p _ _ _ _ _ _ _ _ _ _ _ _ _) || + refine (p _ _ _ _ _ _ _ _ _ _ _ _) || + refine (p _ _ _ _ _ _ _ _ _ _ _) || + refine (p _ _ _ _ _ _ _ _ _ _) || + refine (p _ _ _ _ _ _ _ _ _) || + refine (p _ _ _ _ _ _ _ _) || + refine (p _ _ _ _ _ _ _) || + refine (p _ _ _ _ _ _) || + refine (p _ _ _ _ _) || + refine (p _ _ _ _) || + refine (p _ _ _) || + refine (p _ _) || + refine (p _) || + refine p. (** Tactical [on_call f tac] applies [tac] on any application of [f] in the hypothesis or goal. *) @@ -213,21 +233,6 @@ Ltac replace_hyp H c := let H' := fresh "H" in assert(H' := c) ; clear H ; rename H' into H. -(** A tactic to refine an hypothesis by supplying some of its arguments. *) - -Ltac refine_hyp c := - let tac H := replace_hyp H c in - match c with - | ?H _ => tac H - | ?H _ _ => tac H - | ?H _ _ _ => tac H - | ?H _ _ _ _ => tac H - | ?H _ _ _ _ _ => tac H - | ?H _ _ _ _ _ _ => tac H - | ?H _ _ _ _ _ _ _ => tac H - | ?H _ _ _ _ _ _ _ _ => tac H - end. - (** The default simplification tactic used by Program is defined by [program_simpl], sometimes [auto] is not enough, better rebind using [Obligation Tactic := tac] in this case, possibly using [program_simplify] to use standard goal-cleaning tactics. *) |