In Coq, is it possible to write a predicate (list Type -> Prop
) that is only provable if all entries of the list are of the form Type@{U}
?
The predicate should accept Types from different universes within the same list. For example, [Type@{U1}; Type@{U2}]
should be accepted, where U1 < U2
. Other types, such as nat
, should not be accepted in the list.
The closest I was able to get is to have the predicate verify that each entry of the list is a universe-like type that has some of the properties of Type@{U}
:
- The universe-like types form a chain, where the previous one is embedded within the next.
Set
is at the start of the chain.- Each universe-like type has an export function that can convert an inhabitant of the universe-like type,
T: UT
, into an inhabitant ofT@{max}
. That is,export: UT -> Type@{max}
.
However, that predicate also accepts types which are not of the form Type%{U}
, such as (Type * nat)%type
.
Require Import List.
Import ListNotations.
Inductive TypeChain: forall (carrier: Type), (carrier -> Type) -> Type :=
| TypeChainSet: TypeChain Set (fun s: Set => s)
| TypeChainNext:
forall prev_carrier prev_export,
TypeChain prev_carrier prev_export ->
forall carrier (export: carrier -> Type) (import: prev_carrier -> carrier),
(forall p: prev_carrier, export (import p) = prev_export p) ->
forall prev_embed,
(export (prev_embed) = prev_carrier) ->
TypeChain carrier export.
Inductive InTypeChain (T: Type):
forall {carrier export}, TypeChain carrier export -> Prop :=
| InTypeChainTop: forall export (chain: TypeChain T export),
InTypeChain T chain
| InTypeChainPrev:
forall prev_carrier prev_export prev_chain,
InTypeChain T prev_chain ->
forall carrier export import export_imported prev_embed prev_embed_matches,
InTypeChain T (TypeChainNext prev_carrier prev_export prev_chain carrier
export import export_imported prev_embed prev_embed_matches).
Definition ListContainsOnlyTypes (l: list Type) :=
exists carrier export (c: TypeChain carrier export),
Forall (fun T => InTypeChain T c) l.
Module GoodExample.
Universe U1 U2.
Constraint U1 < U2.
Definition ChainU2: TypeChain Type@{U2} (fun T => T).
Proof.
unshelve eapply (TypeChainNext Type@{U1}); auto.
unshelve eapply (TypeChainNext Type@{Set}); auto.
unshelve apply TypeChainSet.
Defined.
Example GoodListAccepted: ListContainsOnlyTypes [Type@{U1}; Set; Type@{U2}].
Proof.
eexists.
eexists.
exists ChainU2.
eauto 7 using InTypeChain.
Qed.
End GoodExample.
Module BadExample.
Definition BadChain: TypeChain (Type * nat) (fun T => fst T).
Proof.
unshelve eapply (TypeChainNext Set); auto.
- exact (fun s:Set => (s:Type, 0)).
- exact (Set, 0).
- apply TypeChainSet.
- reflexivity.
- reflexivity.
Defined.
Example BadListAccepted: ListContainsOnlyTypes [(Type * nat)%type; Set].
Proof.
eexists.
eexists.
exists BadChain.
eauto using InTypeChain.
Qed.
End BadExample.
nat
is not equal tonat * nat
in Coq? $\endgroup$nat
andnat * nat
are both countably infinite types. So without adding axioms, you can't prove that they are equal or not equal. $\endgroup$nat = (nat*nat)
as an axiom there will be no inconsistency. Similarly adding the axiom about universesType = Type*nat
does not result in inconsistencies. $\endgroup$(Set -> bool) = Set -> False
, so your claim above is incorrect. $\endgroup$