[Git][monnier/typer][master] Allow "impredicative" universe polymorphism
Stefan pushed to branch master at Stefan / Typer Commits: 634f6df0 by Stefan Monnier at 2019-10-22T21:58:25Z Allow "impredicative" universe polymorphism * samples/hurkens.typer (𝓅): Make it universe-polymorphic. * src/elab.ml (infer_level): New function. (sform_type): Use it. * src/log.ml (log_fatal): Set print_at_log before calling log_msg so the message is printed before raising the exception, otherwise it's lost. * src/opslexp.ml (deep_universe_poly): New const. (sort_compose): Add one more context for k2. Fix k2 scoping. Obey deep_universe_poly. - - - - - 6 changed files: - samples/hurkens.typer - src/builtin.ml - src/elab.ml - src/lexp.ml - src/log.ml - src/opslexp.ml Changes: ===================================== samples/hurkens.typer ===================================== @@ -12,19 +12,21 @@ %%% Code: +* = Type_ (s z); +□ = Type_ (s (s z)); + ⊥ : Type; ⊥ = (p : Type) ≡> p; ¬ : (ℓ : TypeLevel) ≡> Type_ ℓ -> Type_ ℓ; -¬ t = t -> ⊥; - -* = Type; -□ = Type1; +¬ t = t -> ⊥ ; %% 𝓅 is the "powerset". -%% 𝓅 S = (S -> *); FIXME: internal error! -𝓅 : □ -> □; -𝓅 (S : □) = (S -> *); +%% 𝓅 S = (S -> *); +𝓅 : (ℓ : TypeLevel) => Type_ (s ℓ) -> Type_ (s ℓ); +%% FIXME: `?` instead of `ℓ` below leads to a type error because it +%% infers a type `Type_ (s (ℓ ∪ ℓ))` instead of `Type_ (s ℓ)` :-( +𝓅 S = (S -> Type_ ℓ); 𝓅𝓅 S = 𝓅 (𝓅 S); %%%% A "powerful" universe (U, σ, τ). ===================================== src/builtin.ml ===================================== @@ -1,6 +1,6 @@ (* builtin.ml --- Infrastructure to define built-in primitives * - * Copyright (C) 2016-2018 Free Software Foundation, Inc. + * Copyright (C) 2016-2019 Free Software Foundation, Inc. * * Author: Pierre Delaunay <pierre.delaunay@hec.ca> * Keywords: languages, lisp, dependent types. ===================================== src/elab.ml ===================================== @@ -1504,7 +1504,7 @@ let rec sform_lambda kind ctx loc sargs ot = * so auto-add a corresponding Lambda wrapper! * FIXME: This should be moved to a macro. *) -> (* FIXME: Here we end up adding a local variable `v` whose - * name is lot lexically present, so there's a risk of + * name is not lexically present, so there's a risk of * name capture. We should make those vars anonymous? *) let nctx = ectx_extend ctx v Variable lt1 in (* FIXME: Don't go back to sform_lambda, but use an internal @@ -1556,6 +1556,16 @@ let sform_letin ctx loc sargs ot = match sargs with | _ -> sexp_error loc "Unrecognized let_in_ expression"; sform_dummy_ret ctx loc +let rec infer_level ctx se : lexp = + match se with + | Symbol (_, "z") -> mkSortLevel SLz + | Symbol _ -> check se type_level ctx + | Node (Symbol (_, "s"), [se]) + -> mkSortLevel (SLsucc (infer_level ctx se)) + | _ -> let l = (sexp_location se) in + (sexp_error l ("Unrecognized TypeLevel: " ^ sexp_string se); + newMetavar (ectx_to_lctx ctx) dummy_scope_level (l, None) type_level) + (* Actually `Type_` could also be defined as a plain constant * Lambda("l", TypeLevel, Sort (Stype (Var "l"))) * But it would be less efficient (such a lambda can't be passed as argument @@ -1564,11 +1574,11 @@ let sform_letin ctx loc sargs ot = match sargs with * allow such a lambda. *) let sform_type ctx loc sargs ot = match sargs with - | [l] -> let l, _ = infer l ctx in - (mkSort (loc, Stype l), - Inferred (mkSort (loc, Stype (SortLevel (mkSLsucc l))))) - | _ -> sexp_error loc "##Type_ expects one argument"; - sform_dummy_ret ctx loc + | [se] -> let l = infer_level ctx se in + (mkSort (loc, Stype l), + Inferred (mkSort (loc, Stype (mkSortLevel (mkSLsucc l))))) + | _ -> (sexp_error loc "##Type_ expects one argument"; + sform_dummy_ret ctx loc) let sform_debruijn ctx loc sargs ot = match sargs with ===================================== src/lexp.ml ===================================== @@ -218,7 +218,7 @@ let mkSLlub' (e1, e2) = match (e1, e2) with let mkSLsucc e = match e with | SortLevel _ | Var _ | Metavar _ | Susp _ -> SLsucc e - | _ -> Log.log_fatal ~section:"internal" "SLsucc of non-level" + | _ -> Log.log_fatal ~section:"internal" "SLsucc of non-level " (********* Helper functions to use the Subst operations *********) (* This basically "ties the knot" between Subst and Lexp. ===================================== src/log.ml ===================================== @@ -159,7 +159,7 @@ let set_typer_log_level_str str = with _ -> set_typer_log_level (level_of_string str) -let increment_log_level () = +let increment_log_level () : unit = typer_log_config.level |> int_of_level |> (+) 1 @@ -189,6 +189,7 @@ exception Stop_Compilation of string let stop_compilation s = raise (Stop_Compilation s) let log_fatal ?section ?print_action ?loc m = + typer_log_config.print_at_log <- true; log_msg Fatal ~kind:"[X] Fatal " ?section ?print_action ?loc m; internal_error "Compiler Fatal Error" let log_error = log_msg Error ?kind:None ===================================== src/opslexp.ml ===================================== @@ -44,9 +44,14 @@ let warning_tc = Log.log_warning ~section:"TC" (* `conv_erase` is supposed to be safe according to the ICC papers. *) let conv_erase = true (* Makes conv ignore erased terms. *) -(* The safety of `impredicative_erase` is unknown. But I like the idea. *) +(* `impredicative_erase` is inconsistent: as shown in samples/hurkens.typer + * it allows the definition of an inf-looping expression of type ⊥. *) let impredicative_erase = true (* Allows erasable args to be impredicative. *) +(* The safety of `deep_universe_poly` is unknown. + * But I also like the idea. *) +let deep_universe_poly = true (* Assume arg is TypeLevel.z when erasable. *) + (* Lexp context *) let lookup_type = DB.lctx_lookup_type @@ -343,19 +348,24 @@ type sort_compose_result | SortK1NotType | SortK2NotType -let sort_compose ctx l ak k1 k2 = +let sort_compose ctx1 ctx2 l ak k1 k2 = (* BEWARE! Technically `k2` can refer to `v`, but this should only happen - * if `v` is a TypeLevel, and in that case sort_compose - * should ignore `k2` and return TypeOmega anyway. *) - let k2 = mkSusp k2 (S.substitute impossible) in - match (lexp_whnf k1 ctx, lexp_whnf k2 ctx) with + * if `v` is a TypeLevel. *) + match (lexp_whnf k1 ctx1, lexp_whnf k2 ctx2) with | (Sort (_, s1), Sort (_, s2)) - (* FIXME: fix scoping of `k2` and `s2`. *) -> (match s1, s2 with | (Stype l1, Stype l2) -> if ak == P.Aerasable && impredicative_erase - then SortResult k2 - else SortResult (mkSort (l, Stype (mkSLlub ctx l1 l2))) + then SortResult (mkSusp k2 (S.substitute impossible)) + else let l2' = (mkSusp l2 (S.substitute impossible)) in + SortResult (mkSort (l, Stype (mkSLlub ctx1 l1 l2'))) + | (StypeLevel, Stype l2) + when ak == P.Aerasable && deep_universe_poly + (* The safety/soundness of this rule is completely unknown. + * It's pretty powerful, e.g. allows tuples containing + * level-polymorphic functions, and makes impredicative-encoding + * of data types almost(just?) as flexible as inductive types. *) + -> SortResult (mkSusp k2 (S.substitute DB.level0)) | (StypeLevel, Stype _) | (StypeLevel, StypeOmega) (* This might be safe, but I don't think it adds much power. @@ -483,7 +493,7 @@ let rec check'' erased ctx e = -> (let k1 = check_type erased ctx t1 in let nctx = DB.lexp_ctx_cons ctx v Variable t1 in let k2 = check_type (DB.set_sink 1 erased) nctx t2 in - match sort_compose ctx l ak k1 k2 with + match sort_compose ctx nctx l ak k1 k2 with | SortResult k -> k | SortInvalid -> error_tc ~loc:l "Invalid arrow: inner TypelLevel argument"; @@ -805,7 +815,7 @@ let rec get_type ctx e = -> (let k1 = get_type ctx t1 in let nctx = DB.lexp_ctx_cons ctx v Variable t1 in let k2 = get_type nctx t2 in - match sort_compose ctx l ak k1 k2 with + match sort_compose ctx nctx l ak k1 k2 with | SortResult k -> k | _ -> mkSort (l, StypeOmega)) | Lambda (ak, ((l,_) as v), t, e) View it on GitLab: https://gitlab.com/monnier/typer/commit/634f6df0a52c10ba036f99e3cee3f7be47a3... -- View it on GitLab: https://gitlab.com/monnier/typer/commit/634f6df0a52c10ba036f99e3cee3f7be47a3... You're receiving this email because of your account on gitlab.com.
Afficher les réponses par date
participants (1)
-
Stefan