123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238(* This file is free software, part of Zipperposition. See file "license" for more details. *)(** {1 Inductive Types} *)moduleT=Termletsection=Util.Section.make"ind_ty"(** Constructor for an inductive type *)typeconstructor={cstor_name:ID.t;cstor_ty:Type.t;cstor_args:(Type.t*projector)list;}(** A projector for a given constructor and argument position *)andprojector={p_id:ID.t;p_ty:Type.t;p_index:int;(* index of projected argument *)p_cstor:constructorlazy_t;}(** {5 Inductive Types} *)(** An inductive type, along with its set of constructors *)typet={ty_id:ID.t;(* name *)ty_vars:Type.tHVar.tlist;(* list of variables *)ty_pattern:Type.t;(* equal to [id ty_vars] *)ty_constructors:constructorlist;(* constructors, all returning [pattern] and containing
no other type variables than [ty_vars] *)ty_is_rec:boollazy_t;(* true iff the type is (mutually) recursive *)ty_proof:Proof.t;}letequalab=ID.equala.ty_idb.ty_idtypeid_or_tybuiltin=|IofID.t|BofType.builtinexceptionInvalidDeclofstringexceptionNotAnInductiveConstructorofID.texceptionNotAnInductiveTypeofID.tlet()=letspf=CCFormat.sprintfinPrintexc.register_printer(function|InvalidDeclmsg->Some(spf"@[<2>invalid declaration:@ %s@]"msg)|NotAnInductiveTypeid->Some(spf"%a is not an inductive type"ID.ppid)|NotAnInductiveConstructorid->Some(spf"%a is not an inductive constructor"ID.ppid)|_->None)exceptionPayload_ind_typeoftexceptionPayload_ind_cstorofconstructor*texceptionPayload_ind_projectorofprojectorletinvalid_decl_msg=raise(InvalidDeclmsg)letinvalid_declf_fmt=CCFormat.ksprintffmt~f:invalid_decl_letppoutty=letppvarsout=function[]->()|l->Format.fprintfout" %a"(Util.pp_listHVar.pp)linFormat.fprintfout"@[%a%a@]"ID.ppty.ty_idppvarsty.ty_varslettype_hdty=let_,_,ret=Type.open_poly_funtyinmatchType.viewretwith|Type.Builtinb->Some(Bb)|Type.App(s,_)->Some(Is)|_->Nonelettype_hd_exnty=matchtype_hdtywith|Someres->res|None->invalid_declf_"expected function type,@ got `@[%a@]`"Type.pptyletas_inductive_tyid=ID.payload_findid~f:(function|Payload_ind_typety->Somety|_->None)letas_inductive_ty_exnid=matchas_inductive_tyidwith|Somety->ty|None->invalid_declf_"%a is not an inductive type"ID.ppidletis_inductive_tyid=matchas_inductive_tyidwithSome_->true|None->falseletis_inductive_typety=matchtype_hdtywith|Some(Iid)->is_inductive_tyid|Some(B_)|None->falseletis_inductive_simple_typety=tryis_inductive_ty(TypedSTerm.head_exnty)withNot_found->falseletas_inductive_typety=matchType.viewtywith|Type.App(id,l)->beginmatchas_inductive_tyidwith|None->None|Someity->Some(ity,l)end|Type.Fun_|Type.Forall_|Type.Builtin_|Type.DB_|Type.Var_->Noneletas_inductive_type_exnty=as_inductive_typety|>CCOpt.get_exnletis_recursive(t:t)=letnew_=Lazy.is_valt.ty_is_recinletres=Lazy.forcet.ty_is_recinifnew_then(Util.debugf~section3"(@[is_recursive@ :ty %a@ :res %B@])"(funk->kpptres););resletproof(t:t):Proof.t=t.ty_proof(* is [top] recursive? *)letis_rec_(top:t):bool=letrecfind_in_ity(seen:tlist)(ity:t):bool=ifCCList.mem~eq:equalityseenthenfalse(* loop *)else(letseen=ity::seeninList.exists(funcstor->find_in_ty_argsseencstor.cstor_ty)ity.ty_constructors)andfind_in_ty_argsseenty=matchType.viewtywith|Type.Forallty'->find_in_ty_argsseenty'|Type.Fun(args,_)->List.exists(find_in_tyseen)args|Type.App_|Type.Builtin_|Type.Var_|Type.DB_->falseandfind_in_ty(seen:tlist)(ty:Type.t)=matchType.viewtywith|Type.Forallty'->find_in_tyseenty'|Type.App(id,l)->ID.equalidtop.ty_id||List.exists(find_in_tyseen)l|Type.Fun(args,ret)->find_in_tyseenret||List.exists(find_in_tyseen)args|Type.Builtin_|Type.Var_|Type.DB_->falseinfind_in_ity[]top(* declare that the given type is inductive *)letdeclare_tyid~ty_varsconstructors~proof=Util.debugf~section1"declare inductive type %a"(funk->kID.ppid);ifconstructors=[]then(invalid_declf_"Ind_types.declare_ty %a: no constructors provided"ID.ppid;);(* check that [ty] is not declared already *)beginmatchas_inductive_tyidwith|Some_->invalid_declf_"inductive type %a already declared"ID.ppid;|None->()end;letrecity={ty_id=id;ty_vars;ty_pattern=Type.appid(List.mapType.varty_vars);ty_constructors=constructors;ty_is_rec=lazy(is_rec_ity);ty_proof=proof;}in(* map the constructors to [ity] too *)List.iter(func->ID.set_payloadc.cstor_name(Payload_ind_cstor(c,ity));(* declare projectors *)List.iter(fun(_,p)->ID.set_payloadp.p_id(Payload_ind_projectorp)~can_erase:(functionPayload_ind_projector_->true|_->false))c.cstor_args;())constructors;(* map [id] to [ity] *)ID.set_payloadid(Payload_ind_typeity);ity(** {5 Constructors} *)letmk_constructoridtyargs=letrecc=lazy(letargs=List.mapi(funi(ty_arg,(p_id,p_ty))->letp={p_id;p_ty;p_cstor=c;p_index=i}inty_arg,p)argsin{cstor_name=id;cstor_ty=ty;cstor_args=args})inLazy.forcecletas_constructorid=ID.payload_findid~f:(function|Payload_ind_cstor(cstor,ity)->Some(cstor,ity)|_->None)letas_constructor_exnid=matchas_constructoridwith|None->raise(NotAnInductiveConstructorid)|Somex->xletis_constructors=matchas_constructorswithSome_->true|None->falseletcontains_inductive_typest=T.Seq.subtermst|>Iter.exists(funt->is_inductive_type(T.tyt))(** {5 Projectors} *)letprojector_idp=p.p_idletprojector_typ=p.p_tyletprojector_idxp=p.p_indexletprojector_cstorp=Lazy.forcep.p_cstorletas_projectorid=ID.payload_findid~f:(function|Payload_ind_projectorp->Somep|_->None)