123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183openPpopenEConstrletexample_sortsigma=(* creating a new sort requires that universes should be recorded
in the evd datastructure, so this datastructure also needs to be
passed around. *)letsigma,s=Evd.new_sort_variableEvd.univ_rigidsigmainletnew_type=mkSortsinsigma,new_typeletc_oneenvsigma=(* In the general case, global references may refer to universe polymorphic
objects, and their universe has to be made afresh when creating an instance. *)letgr_S=Coqlib.lib_ref"num.nat.S"in(* the long name of "S" was found with the command "Print Registered." *)letgr_O=Coqlib.lib_ref"num.nat.O"inletsigma,c_O=Evd.fresh_globalenvsigmagr_Oinletsigma,c_S=Evd.fresh_globalenvsigmagr_Sin(* Here is the construction of a new term by applying functions to argument. *)sigma,mkApp(c_S,[|c_O|])letdangling_identityenvsigma=(* I call this a dangling identity, because it is not polymorph, but
the type on which it applies is left unspecified, as it is
represented by an existential variable. The declaration for this
existential variable needs to be added in the evd datastructure. *)letsigma,type_type=example_sortsigmainletsigma,arg_type=Evarutil.new_evarenvsigmatype_typein(* Notice the use of a De Bruijn index for the inner occurrence of the
bound variable. *)sigma,mkLambda(nameR(Names.Id.of_string"x"),arg_type,mkRel1)letdangling_identity2envsigma=(* This example uses directly a function that produces an evar that
is meant to be a type. *)letsigma,(arg_type,type_type)=Evarutil.new_type_evarenvsigmaEvd.univ_rigidinsigma,mkLambda(nameR(Names.Id.of_string"x"),arg_type,mkRel1)letexample_sort_app_lambda()=letenv=Global.env()inletsigma=Evd.from_envenvinletsigma,c_v=c_oneenvsigmain(* dangling_identity and dangling_identity2 can be used interchangeably here *)letsigma,c_f=dangling_identity2envsigmainletc_1=mkApp(c_f,[|c_v|])inlet_=Feedback.msg_notice(Printer.pr_econstr_envenvsigmac_1)in(* type verification happens here. Type verification will update
existential variable information in the evd part. *)letsigma,the_type=Typing.type_ofenvsigmac_1in(* At display time, you will notice that the system knows about the
existential variable being instantiated to the "nat" type, even
though c_1 still contains the meta-variable. *)Feedback.msg_notice((Printer.pr_econstr_envenvsigmac_1)++str" has type "++(Printer.pr_econstr_envenvsigmathe_type))letc_Senvsigma=letgr=Coqlib.lib_ref"num.nat.S"inEvd.fresh_globalenvsigmagrletc_Oenvsigma=letgr=Coqlib.lib_ref"num.nat.O"inEvd.fresh_globalenvsigmagrletc_Eenvsigma=letgr=Coqlib.lib_ref"Tuto3.EvenNat"inEvd.fresh_globalenvsigmagrletc_Denvsigma=letgr=Coqlib.lib_ref"Tuto3.tuto_div2"inEvd.fresh_globalenvsigmagrletc_Qenvsigma=letgr=Coqlib.lib_ref"core.eq.type"inEvd.fresh_globalenvsigmagrletc_Renvsigma=letgr=Coqlib.lib_ref"core.eq.eq_refl"inEvd.fresh_globalenvsigmagrletc_Nenvsigma=letgr=Coqlib.lib_ref"num.nat.type"inEvd.fresh_globalenvsigmagrletc_Cenvsigma=letgr=Coqlib.lib_ref"Tuto3.C"inEvd.fresh_globalenvsigmagrletc_Fenvsigma=letgr=Coqlib.lib_ref"Tuto3.S_ev"inEvd.fresh_globalenvsigmagrletc_Penvsigma=letgr=Coqlib.lib_ref"Tuto3.s_half_proof"inEvd.fresh_globalenvsigmagr(* If c_S was universe polymorphic, we should have created a new constant
at each iteration of buildup. *)letmk_natenvsigman=letsigma,c_S=c_Senvsigmainletsigma,c_O=c_Oenvsigmainletrecbuildup=function|0->c_O|n->mkApp(c_S,[|buildup(n-1)|])inifn<=0thensigma,c_Oelsesigma,buildupnletexample_classesn=letenv=Global.env()inletsigma=Evd.from_envenvinletsigma,c_n=mk_natenvsigmaninletsigma,n_half=mk_natenvsigma(n/2)inletsigma,c_N=c_Nenvsigmainletsigma,c_div=c_Denvsigmainletsigma,c_even=c_Eenvsigmainletsigma,c_Q=c_Qenvsigmainletsigma,c_R=c_Renvsigmainletarg_type=mkApp(c_even,[|c_n|])inletsigma0=sigmainletsigma,instance=Evarutil.new_evarenvsigmaarg_typeinletc_half=mkApp(c_div,[|c_n;instance|])inlet_=Feedback.msg_notice(Printer.pr_econstr_envenvsigmac_half)inletsigma,the_type=Typing.type_ofenvsigmac_halfinlet_=Feedback.msg_notice(Printer.pr_econstr_envenvsigmac_half)inletproved_equality=mkCast(mkApp(c_R,[|c_N;c_half|]),Constr.DEFAULTcast,mkApp(c_Q,[|c_N;c_half;n_half|]))in(* This is where we force the system to compute with type classes. *)(* Question to coq developers: why do we pass two evd arguments to
solve_remaining_evars? Is the choice of sigma0 relevant here? *)letsigma=Pretyping.solve_remaining_evars(Pretyping.default_inference_flagstrue)envsigma~initial:sigma0inletsigma,final_type=Typing.type_ofenvsigmaproved_equalityinFeedback.msg_notice(Printer.pr_econstr_envenvsigmaproved_equality)(* This function, together with definitions in Data.v, shows how to
trigger automatic proofs at the time of typechecking, based on
canonical structures.
n is a number for which we want to find the half (and a proof that
this half is indeed the half)
*)letexample_canonicaln=letenv=Global.env()inletsigma=Evd.from_envenvin(* Construct a natural representation of this integer. *)letsigma,c_n=mk_natenvsigmanin(* terms for "nat", "eq", "S_ev", "eq_refl", "C" *)letsigma,c_N=c_Nenvsigmainletsigma,c_F=c_Fenvsigmainletsigma,c_R=c_Renvsigmainletsigma,c_C=c_Cenvsigmainletsigma,c_P=c_Penvsigmain(* the last argument of C *)letrefl_term=mkApp(c_R,[|c_N;c_n|])in(* Now we build two existential variables, for the value of the half and for
the "S_ev" structure that triggers the proof search. *)letsigma,ev1=Evarutil.new_evarenvsigmac_Nin(* This is the type for the second existential variable *)letcsev=mkApp(c_F,[|ev1|])inletsigma,ev2=Evarutil.new_evarenvsigmacsevin(* Now we build the C structure. *)lettest_term=mkApp(c_C,[|c_n;ev1;ev2;refl_term|])in(* Type-checking this term will compute values for the existential variables *)letsigma,final_type=Typing.type_ofenvsigmatest_termin(* The computed type has two parameters, the second one is the proof. *)letvalue=matchkindsigmafinal_typewith|Constr.App(_,[|_;the_half|])->the_half|_->failwith"expecting the whole type to be \"cmp _ the_half\""inlet_=Feedback.msg_notice(Printer.pr_econstr_envenvsigmavalue)in(* I wish for a nicer way to get the value of ev2 in the evar_map *)letprf_struct=of_constr(to_constrsigmaev2)inletthe_prf=mkApp(c_P,[|ev1;prf_struct|])inletsigma,the_statement=Typing.type_ofenvsigmathe_prfinFeedback.msg_notice(Printer.pr_econstr_envenvsigmathe_prf++str" has type "++Printer.pr_econstr_envenvsigmathe_statement)