diff options
-rw-r--r-- | Makefile.common | 3 | ||||
-rw-r--r-- | contrib/subtac/subtac_classes.ml | 18 | ||||
-rw-r--r-- | interp/constrintern.ml | 26 | ||||
-rw-r--r-- | parsing/g_vernac.ml4 | 4 | ||||
-rw-r--r-- | parsing/ppvernac.ml | 2 | ||||
-rw-r--r-- | pretyping/pretyping.ml | 4 | ||||
-rw-r--r-- | pretyping/typeclasses_errors.ml | 3 | ||||
-rw-r--r-- | pretyping/typeclasses_errors.mli | 3 | ||||
-rw-r--r-- | tactics/class_tactics.ml4 | 160 | ||||
-rw-r--r-- | theories/Classes/EquivDec.v | 138 | ||||
-rw-r--r-- | theories/Classes/Equivalence.v | 4 | ||||
-rw-r--r-- | theories/Classes/Morphisms.v | 3 | ||||
-rw-r--r-- | theories/Classes/RelationClasses.v | 35 | ||||
-rw-r--r-- | theories/Classes/SetoidClass.v | 2 | ||||
-rw-r--r-- | theories/Classes/SetoidDec.v | 2 | ||||
-rw-r--r-- | toplevel/classes.ml | 12 | ||||
-rw-r--r-- | toplevel/classes.mli | 2 | ||||
-rw-r--r-- | toplevel/himsg.ml | 5 | ||||
-rw-r--r-- | toplevel/vernacexpr.ml | 2 |
19 files changed, 297 insertions, 131 deletions
diff --git a/Makefile.common b/Makefile.common index 9c539952f..ddd13223e 100644 --- a/Makefile.common +++ b/Makefile.common @@ -744,7 +744,8 @@ UNICODEVO:= theories/Unicode/Utf8.vo CLASSESVO:= theories/Classes/Init.vo theories/Classes/RelationClasses.vo theories/Classes/Morphisms.vo \ theories/Classes/Functions.vo theories/Classes/Equivalence.vo theories/Classes/SetoidTactics.vo \ - theories/Classes/SetoidClass.vo theories/Classes/SetoidAxioms.vo theories/Classes/SetoidDec.vo + theories/Classes/SetoidClass.vo theories/Classes/SetoidAxioms.vo theories/Classes/EquivDec.vo \ + theories/Classes/SetoidDec.vo THEORIESVO:=\ $(INITVO) $(LOGICVO) $(ARITHVO) $(BOOLVO) $(NARITHVO) $(ZARITHVO) \ diff --git a/contrib/subtac/subtac_classes.ml b/contrib/subtac/subtac_classes.ml index 0c99fe16e..d65243680 100644 --- a/contrib/subtac/subtac_classes.ml +++ b/contrib/subtac/subtac_classes.ml @@ -136,12 +136,12 @@ let new_instance ctx (instid, bk, cl) props pri = let gen_ctx = Implicit_quantifiers.binder_list_of_ids gen_ids in let ctx, avoid = Classes.name_typeclass_binders bound ctx in let ctx = List.rev_append gen_ctx ctx in - let k, ctx', subst = + let k, ctx', imps, subst = let c = Command.generalize_constr_expr tclass ctx in - let c' = interp_type_evars isevars env c in + let c', imps = interp_type_evars_impls ~evdref:isevars env c in let ctx, c = Classes.decompose_named_assum c' in let cl, args = Typeclasses.dest_class_app c in - cl, ctx, substitution_of_constrs (List.map snd cl.cl_context) (List.rev (Array.to_list args)) + cl, ctx, imps, substitution_of_constrs (List.map snd cl.cl_context) (List.rev (Array.to_list args)) in let id = match snd instid with @@ -194,11 +194,13 @@ let new_instance ctx (instid, bk, cl) props pri = Evarutil.nf_isevar !isevars t in isevars := undefined_evars !isevars; - let imps = - Util.list_map_i - (fun i (na, b, t) -> ExplByPos (i, Some na), (true, true)) - 1 ctx' - in +(* let imps = *) +(* Util.list_map_i *) +(* (fun i binder -> *) +(* match binder with *) +(* ExplByPos (i, Some na), (true, true)) *) +(* 1 ctx *) +(* in *) let hook cst = let inst = { is_class = k; diff --git a/interp/constrintern.ml b/interp/constrintern.ml index ee245450b..ce445c3f6 100644 --- a/interp/constrintern.ml +++ b/interp/constrintern.ml @@ -1187,25 +1187,31 @@ let interp_open_constr sigma env c = let interp_constr_judgment sigma env c = Default.understand_judgment sigma env (intern_constr sigma env c) -let interp_constr_evars_gen_impls ?(evdref=ref Evd.empty_evar_defs) +let interp_constr_evars_gen_impls ?evdref env ?(impls=([],[])) kind c = - let c = intern_gen (kind=IsType) ~impls (Evd.evars_of !evdref) env c in - let imps = implicits_of_rawterm c in - Default.understand_tcc_evars evdref env kind c, imps + match evdref with + | None -> + let c = intern_gen (kind=IsType) ~impls Evd.empty env c in + let imps = implicits_of_rawterm c in + Default.understand_gen kind Evd.empty env c, imps + | Some evdref -> + let c = intern_gen (kind=IsType) ~impls (Evd.evars_of !evdref) env c in + let imps = implicits_of_rawterm c in + Default.understand_tcc_evars evdref env kind c, imps let interp_constr_evars_gen evdref env ?(impls=([],[])) kind c = let c = intern_gen (kind=IsType) ~impls (Evd.evars_of !evdref) env c in Default.understand_tcc_evars evdref env kind c -let interp_casted_constr_evars_impls ?(evdref=ref Evd.empty_evar_defs) +let interp_casted_constr_evars_impls ?evdref env ?(impls=([],[])) c typ = - interp_constr_evars_gen_impls ~evdref env ~impls (OfType (Some typ)) c + interp_constr_evars_gen_impls ?evdref env ~impls (OfType (Some typ)) c -let interp_type_evars_impls ?(evdref=ref Evd.empty_evar_defs) env ?(impls=([],[])) c = - interp_constr_evars_gen_impls ~evdref env IsType ~impls c +let interp_type_evars_impls ?evdref env ?(impls=([],[])) c = + interp_constr_evars_gen_impls ?evdref env IsType ~impls c -let interp_constr_evars_impls ?(evdref=ref Evd.empty_evar_defs) env ?(impls=([],[])) c = - interp_constr_evars_gen_impls ~evdref env (OfType None) ~impls c +let interp_constr_evars_impls ?evdref env ?(impls=([],[])) c = + interp_constr_evars_gen_impls ?evdref env (OfType None) ~impls c let interp_casted_constr_evars evdref env ?(impls=([],[])) c typ = interp_constr_evars_gen evdref env ~impls (OfType (Some typ)) c diff --git a/parsing/g_vernac.ml4 b/parsing/g_vernac.ml4 index 40c6180f0..df29d5096 100644 --- a/parsing/g_vernac.ml4 +++ b/parsing/g_vernac.ml4 @@ -475,14 +475,14 @@ GEXTEND Gram (* Type classes, new syntax without artificial sup. *) | IDENT "Class"; qid = identref; pars = binders_let; - s = [ ":"; c = sort -> loc, c | -> (loc,Rawterm.RType None) ]; + s = [ ":"; c = sort -> Some (loc, c) | -> None ]; props = typeclass_field_types -> VernacClass (qid, pars, s, [], props) (* Type classes *) | IDENT "Class"; sup = OPT [ l = delimited_binders_let; "=>" -> l ]; qid = identref; pars = binders_let; - s = [ ":"; c = sort -> loc, c | -> (loc,Rawterm.RType None) ]; + s = [ ":"; c = sort -> Some (loc, c) | -> None ]; props = typeclass_field_types -> VernacClass (qid, pars, s, (match sup with None -> [] | Some l -> l), props) diff --git a/parsing/ppvernac.ml b/parsing/ppvernac.ml index 92d56e078..7ca1964ea 100644 --- a/parsing/ppvernac.ml +++ b/parsing/ppvernac.ml @@ -701,7 +701,7 @@ let rec pr_vernac = function str"Class" ++ spc () ++ pr_lident id ++ (* prlist_with_sep (spc) (pr_lident_constr (spc() ++ str ":" ++ spc())) par ++ *) pr_and_type_binders_arg par ++ - spc () ++ str":" ++ spc() ++ pr_rawsort (snd ar) ++ + (match ar with Some ar -> spc () ++ str":" ++ spc() ++ pr_rawsort (snd ar) | None -> mt()) ++ spc () ++ str"where" ++ spc () ++ prlist_with_sep (fun () -> str";" ++ spc()) (fun (lid,oc,c) -> pr_lident_constr ((if oc then str" :>" else str" :") ++ spc()) (lid,c)) props ) diff --git a/pretyping/pretyping.ml b/pretyping/pretyping.ml index 980a5075f..f9fcdb7b6 100644 --- a/pretyping/pretyping.ml +++ b/pretyping/pretyping.ml @@ -700,7 +700,9 @@ module Pretyping_F (Coercion : Coercion.S) = struct let evdref = ref (Evd.create_evar_defs sigma) in let c = pretype_gen evdref env lvar kind c in let evd,_ = consider_remaining_unif_problems env !evdref in - if fail_evar then check_evars env Evd.empty evd c; + if fail_evar then + (let evd = Typeclasses.resolve_typeclasses ~onlyargs:false ~all:false env (evars_of evd) evd in + check_evars env Evd.empty evd c); evd, c (** Entry points of the high-level type synthesis algorithm *) diff --git a/pretyping/typeclasses_errors.ml b/pretyping/typeclasses_errors.ml index 1648f667a..4db826108 100644 --- a/pretyping/typeclasses_errors.ml +++ b/pretyping/typeclasses_errors.ml @@ -28,6 +28,7 @@ type typeclass_error = | NotAClass of constr | UnboundMethod of global_reference * identifier located (* Class name, method *) | NoInstance of identifier located * constr list + | UnsatisfiableConstraints of evar_map | MismatchedContextInstance of contexts * constr_expr list * named_context (* found, expected *) exception TypeClassError of env * typeclass_error @@ -40,4 +41,6 @@ let unbound_method env cid id = typeclass_error env (UnboundMethod (cid, id)) let no_instance env id args = typeclass_error env (NoInstance (id, args)) +let unsatisfiable_constraints env evm = typeclass_error env (UnsatisfiableConstraints evm) + let mismatched_ctx_inst env c n m = typeclass_error env (MismatchedContextInstance (c, n, m)) diff --git a/pretyping/typeclasses_errors.mli b/pretyping/typeclasses_errors.mli index 82e37f41d..a697087d2 100644 --- a/pretyping/typeclasses_errors.mli +++ b/pretyping/typeclasses_errors.mli @@ -28,6 +28,7 @@ type typeclass_error = | NotAClass of constr | UnboundMethod of global_reference * identifier located (* Class name, method *) | NoInstance of identifier located * constr list + | UnsatisfiableConstraints of evar_map | MismatchedContextInstance of contexts * constr_expr list * named_context (* found, expected *) exception TypeClassError of env * typeclass_error @@ -38,4 +39,6 @@ val unbound_method : env -> global_reference -> identifier located -> 'a val no_instance : env -> identifier located -> constr list -> 'a +val unsatisfiable_constraints : env -> evar_map -> 'a + val mismatched_ctx_inst : env -> contexts -> constr_expr list -> named_context -> 'a diff --git a/tactics/class_tactics.ml4 b/tactics/class_tactics.ml4 index dd93d511c..8d9ee36e9 100644 --- a/tactics/class_tactics.ml4 +++ b/tactics/class_tactics.ml4 @@ -79,7 +79,7 @@ let rec e_trivial_fail_db db_list local_db goal = let hintl = make_resolve_hyp (pf_env g') (project g') d in (e_trivial_fail_db db_list (Hint_db.add_list hintl local_db) g'))) :: - (List.map fst (e_trivial_resolve db_list local_db (pf_concl goal)) ) + (List.map pi1 (e_trivial_resolve db_list local_db (pf_concl goal)) ) in tclFIRST (List.map tclCOMPLETE tacl) goal @@ -93,36 +93,32 @@ and e_my_find_search db_list local_db hdc concl = in let tac_of_hint = fun {pri=b; pat = p; code=t} -> - (b, - let tac = - match t with - | Res_pf (term,cl) -> unify_resolve (term,cl) - | ERes_pf (term,cl) -> unify_e_resolve (term,cl) - | Give_exact (c) -> e_give_exact c - | Res_pf_THEN_trivial_fail (term,cl) -> - tclTHEN (unify_e_resolve (term,cl)) - (e_trivial_fail_db db_list local_db) - | Unfold_nth c -> unfold_in_concl [[],c] - | Extern tacast -> conclPattern concl - (Option.get p) tacast - in - (tac,fmt_autotactic t)) + let tac = + match t with + | Res_pf (term,cl) -> unify_resolve (term,cl) + | ERes_pf (term,cl) -> unify_e_resolve (term,cl) + | Give_exact (c) -> e_give_exact c + | Res_pf_THEN_trivial_fail (term,cl) -> + tclTHEN (unify_e_resolve (term,cl)) + (e_trivial_fail_db db_list local_db) + | Unfold_nth c -> unfold_in_concl [[],c] + | Extern tacast -> conclPattern concl + (Option.get p) tacast + in + (tac,b,fmt_autotactic t) in List.map tac_of_hint hintl and e_trivial_resolve db_list local_db gl = try - Auto.priority - (e_my_find_search db_list local_db - (List.hd (head_constr_bound gl [])) gl) + e_my_find_search db_list local_db + (List.hd (head_constr_bound gl [])) gl with Bound | Not_found -> [] let e_possible_resolve db_list local_db gl = try - List.map snd - (List.sort (fun (b, _) (b', _) -> b - b') - (e_my_find_search db_list local_db - (List.hd (head_constr_bound gl [])) gl)) + e_my_find_search db_list local_db + (List.hd (head_constr_bound gl [])) gl with Bound | Not_found -> [] let find_first_goal gls = @@ -132,6 +128,7 @@ let find_first_goal gls = type search_state = { depth : int; (*r depth of search before failing *) tacres : goal list sigma * validation; + pri : int; last_tactic : std_ppcmds; custom_tactic : tactic; dblist : Auto.Hint_db.t list; @@ -152,24 +149,24 @@ module SearchProblem = struct prlist (pr_ev evars) (sig_it gls) let filter_tactics (glls,v) l = -(* if !debug then *) -(* (let _ = Proof_trees.db_pr_goal (List.hd (sig_it glls)) in *) -(* let evars = Evarutil.nf_evars (Refiner.project glls) in *) - (* msg (str"Goal: " ++ pr_ev evars (List.hd (sig_it glls)) ++ str"\n")); *) + if !debug then + (let _ = Proof_trees.db_pr_goal (List.hd (sig_it glls)) in + let evars = Evarutil.nf_evars (Refiner.project glls) in + msg (str"Goal: " ++ pr_ev evars (List.hd (sig_it glls)) ++ str"\n")); let rec aux = function | [] -> [] - | (tac,pptac) :: tacl -> + | (tac,pri,pptac) :: tacl -> try - (* if !debug then msg (str"\nTrying tactic: " ++ pptac ++ str"\n"); *) + if !debug then msg (str"\nTrying tactic: " ++ pptac ++ str"\n"); let (lgls,ptl) = apply_tac_list tac glls in let v' p = v (ptl p) in - (* if !debug then *) - (* begin *) - (* let evars = Evarutil.nf_evars (Refiner.project glls) in *) - (* msg (str"\nOn goal: " ++ pr_ev evars (List.hd (sig_it glls)) ++ str"\n"); *) - (* msg (hov 1 (pptac ++ str" gives: \n" ++ pr_goals lgls ++ str"\n")) *) - (* end; *) - ((lgls,v'),pptac) :: aux tacl + if !debug then + begin + let evars = Evarutil.nf_evars (Refiner.project glls) in + msg (str"\nOn goal: " ++ pr_ev evars (List.hd (sig_it glls)) ++ str"\n"); + msg (hov 1 (pptac ++ str" gives: \n" ++ pr_goals lgls ++ str"\n")) + end; + ((lgls,v'),pri,pptac) :: aux tacl with e when Logic.catchable_exception e -> (* if !debug then msg (str"failed\n"); *) aux tacl @@ -179,14 +176,17 @@ module SearchProblem = struct Evd.fold (fun ev evi acc -> if evi.evar_body = Evar_empty then succ acc else acc) s 0 (* Ordering of states is lexicographic on depth (greatest first) then - number of remaining goals. *) + priority (lowest pri means higher priority), then number of remaining goals. *) let compare s s' = let d = s'.depth - s.depth in let nbgoals s = List.length (sig_it (fst s.tacres)) + nb_empty_evars (sig_sig (fst s.tacres)) in - if d <> 0 then d else nbgoals s - nbgoals s' + if d <> 0 then d else + let pri = s.pri - s'.pri in + if pri <> 0 then pri + else nbgoals s - nbgoals s' let branching s = if s.depth = 0 then @@ -200,16 +200,16 @@ module SearchProblem = struct let l = filter_tactics s.tacres (List.map - (fun id -> (Eauto.e_give_exact_constr (mkVar id), + (fun id -> (Eauto.e_give_exact_constr (mkVar id), 0, (str "exact" ++ spc () ++ pr_id id))) - (pf_ids_of_hyps g)) + (pf_ids_of_hyps g)) in - List.map (fun (res,pp) -> { s with tacres = res; + List.map (fun (res,pri,pp) -> { s with tacres = res; pri = 0; last_tactic = pp; localdb = List.tl s.localdb }) l in let intro_tac = List.map - (fun ((lgls,_) as res,pp) -> + (fun ((lgls,_) as res,pri,pp) -> let g' = first_goal lgls in let hintl = make_resolve_hyp (pf_env g') (project g') (pf_last_hyp g') @@ -217,18 +217,19 @@ module SearchProblem = struct let ldb = Hint_db.add_list hintl (match s.localdb with [] -> assert false | hd :: _ -> hd) in { s with tacres = res; last_tactic = pp; + pri = pri; localdb = ldb :: List.tl s.localdb }) - (filter_tactics s.tacres [Tactics.intro,(str "intro")]) + (filter_tactics s.tacres [Tactics.intro,1,(str "intro")]) in - let possible_resolve ((lgls,_) as res, pp) = + let possible_resolve ((lgls,_) as res, pri, pp) = let nbgl' = List.length (sig_it lgls) in if nbgl' < nbgl then - { s with tacres = res; last_tactic = pp; + { s with tacres = res; last_tactic = pp; pri = pri; localdb = List.tl s.localdb } else { s with depth = pred s.depth; tacres = res; - last_tactic = pp; + last_tactic = pp; pri = pri; localdb = list_addn (nbgl'-nbgl) (List.hd s.localdb) s.localdb } in @@ -255,6 +256,7 @@ module Search = Explore.Make(SearchProblem) let make_initial_state n gls ~(tac:tactic) dblist localdbs = { depth = n; tacres = gls; + pri = 0; last_tactic = (mt ()); custom_tactic = tac; dblist = dblist; @@ -341,13 +343,18 @@ let has_undefined p evd = (evi.evar_body = Evar_empty && p ev evi)) (Evd.evars_of evd) false -let rec resolve_all_evars ~(tac:tactic) debug m env p evd = - let rec aux n evd = - if has_undefined p evd && n > 0 then - let evd' = resolve_all_evars_once ~tac debug m env p evd in - aux (pred n) evd' +let rec resolve_all_evars ~(tac:tactic) debug m env p oevd = +(* let evd = resolve_all_evars_once ~tac debug m env p evd in *) +(* if has_undefined p evd then raise Not_found *) +(* else evd *) + let rec aux n evd = + if has_undefined p evd then + if n > 0 then + let evd' = resolve_all_evars_once ~tac debug m env p evd in + aux (pred n) evd' + else raise Not_found else evd - in aux 3 evd + in aux 3 oevd (** Handling of the state of unfolded constants. *) @@ -449,7 +456,11 @@ let symmetric_proof = lazy (try_find_reference ["Classes"; "RelationClasses"] "s let transitive_type = lazy (try_find_reference ["Classes"; "RelationClasses"] "Transitive") let transitive_proof = lazy (try_find_reference ["Classes"; "RelationClasses"] "transitivity") -let inverse = lazy (gen_constant ["Classes"; "RelationClasses"] "inverse") +let coq_inverse = lazy (gen_constant (* ["Classes"; "RelationClasses"] "inverse" *) + ["Program"; "Basics"] "flip") + +let inverse car rel = mkApp (Lazy.force coq_inverse, [| car ; car; mkProp; rel |]) + let complement = lazy (gen_constant ["Classes"; "RelationClasses"] "complement") let pointwise_relation = lazy (gen_constant ["Classes"; "RelationClasses"] "pointwise_relation") @@ -506,19 +517,22 @@ let build_signature isevars env m (cstrs : 'a option list) (finalcstr : 'a optio | Some x -> f x in let rec aux t l = - let t = Reductionops.whd_betadelta env (Evd.evars_of !isevars) t in + let t = Reductionops.whd_betadeltaiota env (Evd.evars_of !isevars) t in match kind_of_term t, l with | Prod (na, ty, b), obj :: cstrs -> - let (arg, evars) = aux b cstrs in + let (b, arg, evars) = aux b cstrs in + let ty = Reductionops.nf_betaiota ty in let relty = mk_relty ty obj in let arg' = mkApp (Lazy.force respectful, [| ty ; b ; relty ; arg |]) in - arg', (ty, relty) :: evars - | _, _ -> + mkProd(na, ty, b), arg', (ty, relty) :: evars + | _, obj :: _ -> anomaly "build_signature: not enough products" + | _, [] -> (match finalcstr with None -> + let t = Reductionops.nf_betaiota t in let rel = mk_relty t None in - rel, [t, rel] - | Some (t, rel) -> rel, [t, rel]) + t, rel, [t, rel] + | Some (t, rel) -> t, rel, [t, rel]) in aux m cstrs let reflexivity_proof_evar env evars carrier relation x = @@ -570,7 +584,7 @@ let resolve_morphism env sigma oldt m ?(fnewt=fun x -> x) args args' cstr evars let appm = mkApp(m, morphargs) in let appmtype = Typing.type_of env sigma appm in let cstrs = List.map (function None -> None | Some (_, (a, r, _, _)) -> Some (a, r)) (Array.to_list morphobjs') in - let signature, sigargs = build_signature evars env appmtype cstrs cstr (fun (a, r) -> r) in + let appmtype', signature, sigargs = build_signature evars env appmtype cstrs cstr (fun (a, r) -> r) in let cl_args = [| appmtype ; signature ; appm |] in let app = mkApp (Lazy.force morphism_type, cl_args) in let morph = Evarutil.e_new_evar evars env app in @@ -704,7 +718,7 @@ let unify_eqn env sigma hypinfo t = else try (mkApp (symmetric_proof env car rel, [| c1 ; c2 ; prf |]), (car, rel, c2, c1)) with Not_found -> - (prf, (car, mkApp (Lazy.force inverse, [| car ; rel |]), c2, c1)) + (prf, (car, inverse car rel, c2, c1)) in Some (env', res) with _ -> None @@ -759,7 +773,7 @@ let build_new gl env sigma flags occs hypinfo concl cstr evars = with Not_found -> None) in res, occ - | Prod (_, x, b) -> + | Prod (_, x, b) when not (dependent (mkRel 1) b) -> let x', occ = aux env x occ None in let b', occ = aux env b occ None in let res = @@ -791,9 +805,9 @@ let build_new gl env sigma flags occs hypinfo concl cstr evars = | _ -> None, occ in aux env concl 1 cstr -let resolve_all_typeclasses env evd = - resolve_all_evars false (true, 15) env - (fun ev evi -> Typeclasses.class_of_constr evi.Evd.evar_concl <> None) evd +(* let resolve_all_typeclasses env evd = *) +(* resolve_all_evars false (true, 15) env *) +(* (fun ev evi -> Typeclasses.class_of_constr evi.Evd.evar_concl <> None) evd *) let resolve_argument_typeclasses ?(tac=tclIDTAC) d p env evd onlyargs all = let pred = @@ -805,9 +819,15 @@ let resolve_argument_typeclasses ?(tac=tclIDTAC) d p env evd onlyargs all = in try resolve_all_evars ~tac d p env pred evd - with e -> - if all then raise e else evd - + with + | Not_found -> + if all then + (* Unable to satisfy the constraints. *) + Typeclasses_errors.unsatisfiable_constraints env (Evd.evars_of evd) + else evd + | e -> + if all then raise e else evd + let cl_rewrite_tactic = lazy (Tacinterp.interp <:tactic<setoid_rewrite_tac>>) let cl_rewrite_clause_aux ?(flags=default_flags) hypinfo goal_meta occs clause gl = @@ -818,7 +838,7 @@ let cl_rewrite_clause_aux ?(flags=default_flags) hypinfo goal_meta occs clause g in let cstr = match is_hyp with - None -> (mkProp, mkApp (Lazy.force inverse, [| mkProp; Lazy.force impl |])) + None -> (mkProp, inverse mkProp (Lazy.force impl)) | Some _ -> (mkProp, Lazy.force impl) in let evars = ref (Evd.create_evar_defs Evd.empty) in @@ -1147,7 +1167,7 @@ let build_morphism_signature m = | _ -> [] in aux t in - let sig_, evars = build_signature isevars env t cstrs None snd in + let t', sig_, evars = build_signature isevars env t cstrs None snd in let _ = List.iter (fun (ty, rel) -> let default = mkApp (Lazy.force default_relation, [| ty; rel |]) in @@ -1165,7 +1185,7 @@ let default_morphism sign m = let env = Global.env () in let isevars = ref (Evd.create_evar_defs Evd.empty) in let t = Typing.type_of env Evd.empty m in - let sign, evars = + let _, sign, evars = build_signature isevars env t (fst sign) (snd sign) (fun (ty, rel) -> rel) in let morph = diff --git a/theories/Classes/EquivDec.v b/theories/Classes/EquivDec.v new file mode 100644 index 000000000..085023720 --- /dev/null +++ b/theories/Classes/EquivDec.v @@ -0,0 +1,138 @@ +(* -*- coq-prog-args: ("-emacs-U" "-nois") -*- *) +(************************************************************************) +(* v * The Coq Proof Assistant / The Coq Development Team *) +(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *) +(* \VV/ **************************************************************) +(* // * This file is distributed under the terms of the *) +(* * GNU Lesser General Public License Version 2.1 *) +(************************************************************************) + +(* Decidable equivalences. + * + * Author: Matthieu Sozeau + * Institution: LRI, CNRS UMR 8623 - UniversitĂcopyright Paris Sud + * 91405 Orsay, France *) + +(* $Id: FSetAVL_prog.v 616 2007-08-08 12:28:10Z msozeau $ *) + +Set Implicit Arguments. +Unset Strict Implicit. + +(** Export notations. *) + +Require Export Coq.Classes.Equivalence. + +(** The [DecidableSetoid] class asserts decidability of a [Setoid]. It can be useful in proofs to reason more + classically. *) + +Require Import Coq.Logic.Decidable. + +Open Scope equiv_scope. + +Class [ Equivalence A ] => DecidableEquivalence := + setoid_decidable : forall x y : A, decidable (x === y). + +(** The [EqDec] class gives a decision procedure for a particular setoid equality. *) + +Class [ Equivalence A ] => EqDec := + equiv_dec : forall x y : A, { x === y } + { x =/= y }. + +(** We define the [==] overloaded notation for deciding equality. It does not take precedence + of [==] defined in the type scope, hence we can have both at the same time. *) + +Notation " x == y " := (equiv_dec (x :>) (y :>)) (no associativity, at level 70). + +Definition swap_sumbool {A B} (x : { A } + { B }) : { B } + { A } := + match x with + | left H => @right _ _ H + | right H => @left _ _ H + end. + +Require Import Coq.Program.Program. + +Open Local Scope program_scope. + +(** Invert the branches. *) + +Program Definition nequiv_dec [ EqDec A ] (x y : A) : { x =/= y } + { x === y } := swap_sumbool (x == y). + +(** Overloaded notation for inequality. *) + +Infix "=/=" := nequiv_dec (no associativity, at level 70). + +(** Define boolean versions, losing the logical information. *) + +Definition equiv_decb [ EqDec A ] (x y : A) : bool := + if x == y then true else false. + +Definition nequiv_decb [ EqDec A ] (x y : A) : bool := + negb (equiv_decb x y). + +Infix "==b" := equiv_decb (no associativity, at level 70). +Infix "<>b" := nequiv_decb (no associativity, at level 70). + +(** Decidable leibniz equality instances. *) + +Require Import Coq.Arith.Peano_dec. + +(** The equiv is burried inside the setoid, but we can recover it by specifying which setoid we're talking about. *) + +Program Instance nat_eq_eqdec : ! EqDec nat eq := + equiv_dec := eq_nat_dec. + +Require Import Coq.Bool.Bool. + +Program Instance bool_eqdec : ! EqDec bool eq := + equiv_dec := bool_dec. + +Program Instance unit_eqdec : ! EqDec unit eq := + equiv_dec x y := in_left. + + Next Obligation. + Proof. + destruct x ; destruct y. + reflexivity. + Qed. + +Program Instance [ EqDec A eq, EqDec B eq ] => + prod_eqdec : ! EqDec (prod A B) eq := + equiv_dec x y := + dest x as (x1, x2) in + dest y as (y1, y2) in + if x1 == y1 then + if x2 == y2 then in_left + else in_right + else in_right. + + Solve Obligations using unfold complement, equiv ; program_simpl. + +Program Instance [ EqDec A eq, EqDec B eq ] => + sum_eqdec : ! EqDec (sum A B) eq := + equiv_dec x y := + match x, y with + | inl a, inl b => if a == b then in_left else in_right + | inr a, inr b => if a == b then in_left else in_right + | inl _, inr _ | inr _, inl _ => in_right + end. + + Solve Obligations using unfold complement, equiv ; program_simpl. + +(** Objects of function spaces with countable domains like bool have decidable equality. *) + +Require Import Coq.Program.FunctionalExtensionality. + +Program Instance [ EqDec A eq ] => bool_function_eqdec : ! EqDec (bool -> A) eq := + equiv_dec f g := + if f true == g true then + if f false == g false then in_left + else in_right + else in_right. + + Solve Obligations using try red ; unfold equiv, complement ; program_simpl. + + Next Obligation. + Proof. + red. + extensionality x. + destruct x ; auto. + Qed. diff --git a/theories/Classes/Equivalence.v b/theories/Classes/Equivalence.v index 00519ecf4..a4c97fc82 100644 --- a/theories/Classes/Equivalence.v +++ b/theories/Classes/Equivalence.v @@ -109,8 +109,8 @@ Ltac equiv_simplify := repeat equiv_simplify_one. Ltac equivify_tac := match goal with - | [ s : Equivalence ?A, H : ?R ?x ?y |- _ ] => change R with (@equiv A R s) in H - | [ s : Equivalence ?A |- context C [ ?R ?x ?y ] ] => change (R x y) with (@equiv A R s x y) + | [ s : Equivalence ?A ?R, H : ?R ?x ?y |- _ ] => change R with (@equiv A R s) in H + | [ s : Equivalence ?A ?R |- context C [ ?R ?x ?y ] ] => change (R x y) with (@equiv A R s x y) end. Ltac equivify := repeat equivify_tac. diff --git a/theories/Classes/Morphisms.v b/theories/Classes/Morphisms.v index eda2aecaa..b4b217e38 100644 --- a/theories/Classes/Morphisms.v +++ b/theories/Classes/Morphisms.v @@ -453,8 +453,7 @@ Lemma inverse_respectful : forall (A : Type) (R : relation A) (B : Type) (R' : r inverse (R ==> R') ==rel (inverse R ==> inverse R'). Proof. intros. - unfold inverse, flip. - unfold respectful. + unfold flip, respectful. split ; intros ; intuition. Qed. diff --git a/theories/Classes/RelationClasses.v b/theories/Classes/RelationClasses.v index 0ca074589..009ee1e86 100644 --- a/theories/Classes/RelationClasses.v +++ b/theories/Classes/RelationClasses.v @@ -36,7 +36,9 @@ Definition default_relation [ DefaultRelation A R ] : relation A := R. Notation " x ===def y " := (default_relation x y) (at level 70, no associativity). -Definition inverse {A} : relation A -> relation A := flip. +Notation "'inverse' R" := (flip (R:relation _) : relation _) (at level 0). + +(* Definition inverse {A} : relation A -> relation A := flip. *) Definition complement {A} (R : relation A) : relation A := fun x y => R x y -> False. @@ -93,26 +95,6 @@ Program Instance [ Transitive A R ] => flip_Transitive : Transitive (flip R). Solve Obligations using unfold flip ; program_simpl ; clapply transitivity. -(** Have to do it again for Prop. *) - -Program Instance [ Reflexive A (R : relation A) ] => inverse_Reflexive : Reflexive (inverse R) := - reflexivity := reflexivity (R:=R). - -Program Instance [ Irreflexive A (R : relation A) ] => inverse_Irreflexive : Irreflexive (inverse R) := - irreflexivity := irreflexivity (R:=R). - -Program Instance [ Symmetric A (R : relation A) ] => inverse_Symmetric : Symmetric (inverse R). - - Solve Obligations using unfold inverse, flip ; program_simpl ; clapply Symmetric. - -Program Instance [ Asymmetric A (R : relation A) ] => inverse_Asymmetric : Asymmetric (inverse R). - - Solve Obligations using program_simpl ; unfold inverse, flip in * ; intros ; clapply asymmetry. - -Program Instance [ Transitive A (R : relation A) ] => inverse_Transitive : Transitive (inverse R). - - Solve Obligations using unfold inverse, flip ; program_simpl ; clapply transitivity. - Program Instance [ Reflexive A (R : relation A) ] => Reflexive_complement_Irreflexive : Irreflexive (complement R). @@ -148,7 +130,7 @@ Tactic Notation "apply" "*" constr(t) := refine (t _ _ _ _ _) | refine (t _ _ _ _ _ _) | refine (t _ _ _ _ _ _ _) ]. Ltac simpl_relation := - unfold inverse, flip, impl, arrow ; try reduce ; program_simpl ; + unfold flip, impl, arrow ; try reduce ; program_simpl ; try ( solve [ intuition ]). Ltac obligations_tactic ::= simpl_relation. @@ -213,12 +195,11 @@ Class [ Equivalence A eqA ] => Antisymmetric (R : relation A) := Program Instance [ eq : Equivalence A eqA, ! Antisymmetric eq R ] => flip_antiSymmetric : Antisymmetric eq (flip R). -Program Instance [ eq : Equivalence A eqA, ! Antisymmetric eq (R : relation A) ] => - inverse_antiSymmetric : Antisymmetric eq (inverse R). - -(** Leibinz equality [eq] is an equivalence relation. *) +(** Leibinz equality [eq] is an equivalence relation. + The instance has low priority as it is always applicable + if only the type is constrained. *) -Program Instance eq_equivalence : Equivalence A (@eq A). +Program Instance eq_equivalence : Equivalence A (@eq A) | 10. (** Logical equivalence [iff] is an equivalence relation. *) diff --git a/theories/Classes/SetoidClass.v b/theories/Classes/SetoidClass.v index d4da4b8df..d370ffa44 100644 --- a/theories/Classes/SetoidClass.v +++ b/theories/Classes/SetoidClass.v @@ -131,7 +131,7 @@ Implicit Arguments setoid_morphism [[!sa]]. Existing Instance setoid_morphism. Program Definition setoid_partial_app_morphism [ sa : Setoid A ] (x : A) : Morphism (equiv ++> iff) (equiv x) := - Reflexive_partial_app_morphism. + Reflexive_partial_app_morphism x. Existing Instance setoid_partial_app_morphism. diff --git a/theories/Classes/SetoidDec.v b/theories/Classes/SetoidDec.v index 26e1ab244..835294ce3 100644 --- a/theories/Classes/SetoidDec.v +++ b/theories/Classes/SetoidDec.v @@ -40,8 +40,6 @@ Class [ Setoid A ] => EqDec := Notation " x == y " := (equiv_dec (x :>) (y :>)) (no associativity, at level 70). -(** Use program to solve some obligations. *) - Definition swap_sumbool {A B} (x : { A } + { B }) : { B } + { A } := match x with | left H => @right _ _ H diff --git a/toplevel/classes.ml b/toplevel/classes.ml index 9a0a0981e..eda8760a9 100644 --- a/toplevel/classes.ml +++ b/toplevel/classes.ml @@ -253,6 +253,10 @@ let new_class id par ar sup props = (* Interpret the arity *) let arity_imps, fullarity = + let ar = + match ar with + Some ar -> ar | None -> (dummy_loc, Rawterm.RType None) + in let arity = CSort (fst ar, snd ar) in let term = prod_constr_expr (prod_constr_expr arity par) sup in interp_type_evars isevars env0 term @@ -278,11 +282,15 @@ let new_class id par ar sup props = List.iter (fun (_,c,t) -> ce t; match c with Some c -> ce c | None -> ()) (params @ fields); match fields with [(Name proj_name, _, field)] -> - let class_type = it_mkProd_or_LetIn arity params in let class_body = it_mkLambda_or_LetIn field params in + let class_type = + match ar with + Some _ -> Some (it_mkProd_or_LetIn arity params) + | None -> None + in let class_entry = { const_entry_body = class_body; - const_entry_type = Some class_type; + const_entry_type = class_type; const_entry_opaque = false; const_entry_boxed = false } in diff --git a/toplevel/classes.mli b/toplevel/classes.mli index 973845d9c..da00044d9 100644 --- a/toplevel/classes.mli +++ b/toplevel/classes.mli @@ -35,7 +35,7 @@ val infer_super_instances : env -> constr list -> *) val new_class : identifier located -> local_binder list -> - Vernacexpr.sort_expr located -> + Vernacexpr.sort_expr located option -> local_binder list -> binder_list -> unit diff --git a/toplevel/himsg.ml b/toplevel/himsg.ml index 70441e50d..4adfaf6aa 100644 --- a/toplevel/himsg.ml +++ b/toplevel/himsg.ml @@ -488,6 +488,10 @@ let explain_no_instance env (_,id) l = str "applied to arguments" ++ spc () ++ prlist_with_sep pr_spc (pr_lconstr_env env) l +let explain_unsatisfiable_constraints env evm = + str"Unable to satisfy the following typeclass constraints:" ++ fnl() ++ + Evd.pr_evar_map evm + let explain_mismatched_contexts env c i j = str"Mismatched contexts while declaring instance: " ++ brk (1,1) ++ hov 1 (str"Expected:" ++ brk (1, 1) ++ pr_named_context env j) ++ fnl () ++ brk (1,1) ++ @@ -498,6 +502,7 @@ let explain_typeclass_error env err = | NotAClass c -> explain_not_a_class env c | UnboundMethod (cid, id) -> explain_unbound_method env cid id | NoInstance (id, l) -> explain_no_instance env id l + | UnsatisfiableConstraints evm -> explain_unsatisfiable_constraints env evm | MismatchedContextInstance (c, i, j) -> explain_mismatched_contexts env c i j (* Refiner errors *) diff --git a/toplevel/vernacexpr.ml b/toplevel/vernacexpr.ml index ee0c42aa2..4579d43a6 100644 --- a/toplevel/vernacexpr.ml +++ b/toplevel/vernacexpr.ml @@ -228,7 +228,7 @@ type vernac_expr = | VernacClass of lident * (* name *) local_binder list * (* params *) - sort_expr located * (* arity *) + sort_expr located option * (* arity *) local_binder list * (* constraints *) (lident * bool * constr_expr) list (* props, with substructure hints *) |