package lambdapi
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Proof assistant for the λΠ-calculus modulo rewriting
Install
dune-project
Dependency
Authors
Maintainers
Sources
lambdapi-2.0.0.tbz
sha256=66d7d29f7a0d10493b8178c4c3aeb247971e24fab3eba1c54887e1b9a82fe005
sha512=69ecf2406e4c7225ab7f8ebe11624db5d2ab989c8f30f5b6e5d426fd8ef9102f142a2840af16fb9103bb712ebcf7d314635f8b413a05df66e7b7a38548867032
doc/src/lambdapi.core/infer.ml.html
Source file infer.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234(** Generating constraints for type inference and type checking. *) open Timed open Common open Error open Term open Print open Debug open Lplib (** Logging function for typing. *) let log_infr = Logger.make 'i' "infr" "type inference/checking" let log_infr = log_infr.pp (** Given a meta [m] of type [Πx1:a1,..,Πxn:an,b], [set_to_prod d p m] sets [m] to a product term of the form [Πy:m1[x1;..;xn],m2[x1;..;xn;y]] with [m1] and [m2] fresh metavariables, and adds these metavariables to [p]. [d] is the call depth used for debug. *) let set_to_prod : int -> problem -> meta -> unit = fun d p m -> let n = m.meta_arity in let env, s = Env.of_prod_nth [] n !(m.meta_type) in let vs = Env.vars env in let xs = Array.map _Vari vs in (* domain *) let u1 = Env.to_prod env _Type in let m1 = LibMeta.fresh p u1 n in let a = _Meta m1 xs in (* codomain *) let y = new_tvar "y" in let env' = Env.add y (_Meta m1 xs) None env in let u2 = Env.to_prod env' (lift s) in let m2 = LibMeta.fresh p u2 (n+1) in let b = Bindlib.bind_var y (_Meta m2 (Array.append xs [|_Vari y|])) in (* result *) let r = _Prod a b in if Logger.log_enabled () then log_infr (Color.red "%a%a ≔ %a") D.depth d pp_meta m pp_term (Bindlib.unbox r); LibMeta.set p m (Bindlib.unbox (Bindlib.bind_mvar vs r)) (** [conv d p c a b] adds the the constraint [(c,a,b)] in [p], if [a] and [b] are not convertible. [d] is the call depth used for debug. *) let conv : int -> problem -> ctxt -> term -> term -> unit = fun d p c a b -> if not (Eval.pure_eq_modulo c a b) then begin let cstr = (c,a,b) in if Logger.log_enabled () then log_infr (Color.mag "%aadd %a") D.depth d pp_constr cstr; p := {!p with to_solve = cstr::!p.to_solve} end (** Exception that may be raised by type inference. *) exception NotTypable (** [infer d p c t] tries to infer a type for the term [t] in context [c], possibly adding new unification constraints in [p]. The set of metavariables of [p] are updated if some metavariables are instantiated or created. The returned type is well-sorted if the recorded constraints are satisfied. [c] must be well sorted. [d] is the call depth used for debug. @raise NotTypable when the term is not typable (when encountering an abstraction over a kind). *) let rec infer : int -> problem -> ctxt -> term -> term = fun d p c t -> let return v = if Logger.log_enabled () then log_infr "%agot %a" D.depth d pp_term v; v in if Logger.log_enabled () then log_infr "%ainfer %a%a" D.depth d pp_ctxt c pp_term t; match unfold t with | Patt(_,_,_) -> assert false (* Forbidden case. *) | TEnv(_,_) -> assert false (* Forbidden case. *) | Kind -> assert false (* Forbidden case. *) | Wild -> assert false (* Forbidden case. *) | TRef(_) -> assert false (* Forbidden case. *) (* ------------------- c ⊢ Type ⇒ Kind *) | Type -> return mk_Kind (* --------------------------------- c ⊢ Vari x ⇒ Ctxt.type_of x c *) | Vari x -> (try return (Ctxt.type_of x c) with Not_found -> assert false) (* ------------------------------- c ⊢ Symb s ⇒ !(s.sym_type) *) | Symb s -> return !(s.sym_type) (* c ⊢ a ⇐ Type c, x:a ⊢ b ⇒ s in {Type,Kind} ----------------------------------------- c ⊢ Prod(a,b) ⇒ s *) | Prod(a,b) -> check (d+1) p c a mk_Type; let _,b,c' = Ctxt.unbind c a None b in let s = infer (d+1) p c' b in begin match unfold s with | (Type | Kind) as s -> s | _ -> conv d p c' s mk_Type; mk_Type (* Here, we force [s] to be equivalent to [Type] as there is little (no?) chance that it can be a kind. *) end (* c ⊢ a ⇐ Type c, x:a ⊢ t ⇒ b b ≠ Kind -------------------------------------------- c ⊢ Abst(a,t) ⇒ Prod(a,b) *) | Abst(a,t) -> check (d+1) p c a mk_Type; let x,t,c' = Ctxt.unbind c a None t in let b = infer (d+1) p c' t in begin match unfold b with | Kind -> wrn None "Abstraction on [%a] is not allowed." Print.pp_term t; raise NotTypable | _ -> return (mk_Prod(a, Bindlib.unbox (Bindlib.bind_var x (lift b)))) end (* c ⊢ t ⇒ Prod(a,b) c ⊢ u ⇐ a ------------------------------------ c ⊢ Appl(t,u) ⇒ subst b u *) | Appl(t,u) -> (* [get_prod f typ] returns the domain and codomain of [t] if [t] is a product. If [t] is a metavariable, then it instantiates it with a product and calls [get_prod f typ] again. Otherwise, it calls [f typ]. *) let rec get_prod f typ = match unfold typ with | Prod(a,b) -> (a,b) | Meta(m,_) -> set_to_prod d p m; get_prod f typ | _ -> f typ in let get_prod_whnf = (* assumes that its argument is in whnf *) get_prod (fun typ -> let a = LibMeta.make p c mk_Type in (* We force [b] to be of type [Type] as there is little (no?) chance that it can be a kind. *) let b = LibMeta.make_codomain p c a in conv d p c typ (mk_Prod(a,b)); (a,b)) in let get_prod = get_prod (fun typ -> get_prod_whnf (Eval.whnf c typ)) in let a, b = get_prod (infer (d+1) p c t) in check (d+1) p c u a; return (Bindlib.subst b u) (* c ⊢ t ⇐ a c, x:a ≔ t ⊢ u ⇒ b c, x:a ≔ t ⊢ b : s in {Type,Kind} ------------------------------------------------------------------ c ⊢ let x:a ≔ t in u ⇒ let x:a ≔ t in b See Pure type systems with definitions, P. Severi and E. Poll, LFCS 1994, http://doi.org/10.1007/3-540-58140-5_30. *) | LLet(a,t,u) -> check (d+1) p c a mk_Type; check (d+1) p c t a; let x,u,c' = Ctxt.unbind c a (Some t) u in let b = infer (d+1) p c' u in begin match unfold b with | Kind -> wrn None "Abstraction on [%a] is not allowed." Print.pp_term u; raise NotTypable | _ -> let s = infer (d+1) p c' b in begin match unfold s with | Type | Kind -> () | _ -> conv d p c' s mk_Type (* Here, we force [s] to be equivalent to [Type] as there is little (no?) chance that it can be a kind. *) end; let b = Bindlib.unbox (Bindlib.bind_var x (lift b)) in return (mk_LLet(a,t,b)) end (* c ⊢ term_of_meta m ts ⇒ a ---------------------------- c ⊢ Meta(m,ts) ⇒ a *) | Meta(m,ts) -> (* The type of [Meta(m,ts)] is the same as the one obtained by applying to [ts] a new symbol having the same type as [m]. *) let s = Term.create_sym (Sign.current_path()) Privat Const Eager true ("?" ^ LibMeta.name m) !(m.meta_type) [] in if Logger.log_enabled () then log_infr "%areplace meta by fresh symbol" D.depth d; infer d p c (Array.fold_left (fun acc t -> mk_Appl(acc,t)) (mk_Symb s) ts) (** [check d c t a] checks that the term [t] has type [a] in context [c], possibly adding new unification constraints in [p]. [c] must be well-formed and [a] well-sorted. [d] is the call depth used for debug. @raise NotTypable when the term is not typable (when encountering an abstraction over a kind). *) and check : int -> problem -> ctxt -> term -> term -> unit = fun d p c t a -> if Logger.log_enabled () then log_infr "%acheck %a" D.depth d pp_typing (c, t, a); conv d p c (infer (d+1) p c t) a let infer = let open Stdlib in let r = ref mk_Kind in fun d p c t -> Debug.(record_time Typing (fun () -> r := infer d p c t)); !r let check d p c t a = Debug.(record_time Typing (fun () -> check d p c t a)) (** [infer_noexn p c t] returns [None] if the type of [t] in context [c] cannot be inferred, or [Some a] where [a] is some type of [t] in the context [c], possibly adding new constraints in [p]. The metavariables of [p] are updated when a metavariable is instantiated or created. [c] must be well sorted. *) let infer_noexn : problem -> ctxt -> term -> term option = fun p c t -> try if Logger.log_enabled () then log_hndl (Color.blu "infer_noexn %a%a") pp_ctxt c pp_term t; let a = time_of "infer" (fun () -> infer 0 p c t) in if Logger.log_enabled () then log_hndl (Color.blu "@[<v2>@[result of infer_noexn:@ %a@]%a@]") pp_term a (fun fmt constraints -> if constraints <> [] then Format.fprintf fmt ";@ @[constraints:@ %a@]" pp_constrs constraints) !p.to_solve; Some a with NotTypable -> None (** [check_noexn p c t a] tells whether the term [t] has type [a] in the context [c], possibly adding new constraints in |p]. The metavariables of [p] are updated when a metavariable is instantiated or created. The context [c] and the type [a] must be well sorted. *) let check_noexn : problem -> ctxt -> term -> term -> bool = fun p c t a -> try if Logger.log_enabled () then log_hndl (Color.blu "check_noexn %a") pp_typing (c, t, a); time_of "check" (fun () -> check 0 p c t a); if Logger.log_enabled () && !p.to_solve <> [] then log_hndl (Color.blu "result of check_noexn:%a") pp_constrs !p.to_solve; true with NotTypable -> false (** Given a meta [m] of type [Πx1:a1,..,Πxn:an,b], [set_to_prod p m] sets [m] to a product term of the form [Πy:m1[x1;..;xn],m2[x1;..;xn;y]] with [m1] and [m2] fresh metavariables, and adds these metavariables to [p]. *) let set_to_prod = set_to_prod 0
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>