-
Notifications
You must be signed in to change notification settings - Fork 237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Injective type formers are inconsistent #349
Comments
One thing I don't yet understand is where injectivity of type constructors is exactly assumed in our logical encoding. Looking at the generated smt file wasn't able to find it and I would like to play a bit with this ... e.g. to see what exactly would break if we completely removed it. All I could find so far is this (in
but it seems just for refs ... right? |
This is currently rejected by the "only Type0" cardinality check, but it will go through with universes. |
I believe this is a consequence of having a projection operator for type constructors (so, Could a fix be only generating such projector for data constructors and not for type constructors? A small test shows that |
Looking more closely, it all still breaks down as soon as we type a term with So it's a consequence of unrestricted inversion and "typing elimination". As Nik suggested, maybe typing elimination should be restricted to lower-kinded types? |
We tried this in Coq and it indeed seems to be the fault of "typing elimination". In this case typing elimination gives us heterogenous injectivity of Inductive I : (Type -> Type) -> Type :=
| Mk : forall f:(Type->Type), I f.
Axiom typing_elim : forall a e (x:I a), JMeq x (Mk e) -> e = a.
(* Alternative way of writing this, injectivity for JMeq/Mk:
Axiom typing_elim : forall l r, JMeq (Mk l) (Mk r) -> l = r. *)
Lemma injI' : forall (x:Type->Type) (y:Type->Type) (ex : I x), I x = I y -> x = y.
Proof.
intros x y ex H.
assert(X : exists ey : I y, JMeq ex ey). rewrite <- H. now eauto. clear H.
destruct X as [ey Hexy].
destruct ex as [ex'].
destruct ey as [ey'].
now apply typing_elim in Hexy.
Qed. So the second fix to this implies restricting "typing elimination". @nikswamy should we start thinking about how to fix these things? :) |
My default plan was to exclude the problematic injectivity axiom in the Z3 encoding for --universes. But, if you have a better solution by restricting elimination somehow, then sure let's "start thinking about" it. Looks like you guys have already made a nice start, actually : ) |
Unfortunately, there is no injectivity axiom directly assumed in the Z3 encoding (or at least we couldn't find any). Instead, there are at least two "features" of the encoding, each of which allows Z3 to prove injectivity: (1) projection operators for type constructors (#349 (comment)), and (2) unrestricted "typing elimination" (#349 (comment)). We can probably just remove (1) from the encoding without breaking much, but we don't yet have a good fix for (2). |
We encode all injectivity properties using projectors. So, I see the projection operator for type constructors as the injectivity axiom. Let's talk ... |
First step in fixing #349. We can still get injectivity from certain properties of *data* constructors but having projectors for *type* constructors will give us the paradox immediately.
Injectivity of type constructors is known to be inconsistent, so we need to remove it. Fortunately, we used to need it only for the purpose of making heterogeneous path equality and inclusion decidable, none of which we actually need.
Here is the original source of this paradox: |
For anyone wondering about status, here it goes: Are injective type formers gone now? The following now fails as it should:
error is
nik [1 hour ago] nik [45 minutes ago] nik [44 minutes ago] nik [44 minutes ago] catalin [43 minutes ago] nik [3 minutes ago] |
@aseemr and I came upon this issue again today. For a year or more now, we no longer encode projectors for type formers. That's good. But, we still provide equalities between the parameters and indices of an inductive type and the arguments of their data constructors. E.g., Given this,
we get:
The inversion axiom has two parts:
This is the code that does it: The most aggressive fix would be to simply drop the part 2 of the axiom (i.e., the equalities), but this would destroy a lot of code. It would essentially prevent us from getting equalities when matching on things like vector, which would be a showstopper. So, reviving the earlier comment about a restricted inversion axiom, how about we restrict part 2 of the axiom to only to those parameters/indices in which Note, I separated part 2 of the axiom into 2a and 2b, since 2a is related also to issue #65. We would need to exclude 2a altogether in case we wanted to support structural subtyping for inductive types. |
@nikswamy Unfortunately, I don't understand this restriction. Can you explain?
Right, 2a is at odds with subtyping for datatypes. |
Let's leave the subtyping for datatypes issues aside for now. I'd be happy to discuss that further on #65. But note that |
About the restricted inversion: My understanding of the injective type formers paradox is that it ties a kind of knot where the inductive type former is applied to (a version of) itself. An even more restrictive variant of my proposal is to exclude the equality axiom for arguments (parameters or indices) that are themselves type functions. If we can get away with excluding the equality for only functions of type (Type -> Type) (and others similar ones in which Type appears non-strictly positively), so much the better. Yet another proposal above was to restrict the axiom to universe 0 inductives. But, that also seems ad hoc, and perhaps overly restrictive. Besides, our inductive types are universe polymorphic, so we'd have to restrict the axiom to their universe-0 instantiations ... which is a bit tricky/clumsy to do in the current SMT encoding (which erases universes quite early). That said, all of these proposals of mine are rather shallow attempts at plugging the hole exposed by the paradox. I don't have a semantic understanding of what enables the paradox and what would be the most liberal condition to exclude it. |
I was getting confused by the status of this, so here's the updated paradox, still present, in case it helps. The SMT can find it super efficiently it seems. (Funnily enough, I think it depends on not thunking top-level axioms for module Inj
type i (f : Type u#1 -> Type u#0) : Type u#1 =
| Mkinj : i f
val isInj : x:_ -> y:_ -> w:(i x) -> Lemma (requires (i x == i y)) (ensures (x == y))
let isInj x y _ = ()
let p (x : Type u#1) : Type u#0 =
exists a. i a == x /\ ~(a x)
let w : i p = Mkinj
let q = i p
val false_of_pq : p q -> Lemma False
let false_of_pq pq = ()
let pq : p q = assert (exists a. i a == q /\ ~(a q))
let falso () : Lemma False = false_of_pq pq Need to think a bit more about the solutions. Excluding equalities for type functions will definitely reject this ( |
Had a quick look at the thread where this paradox was originally reported: |
I've been working on a universe-based criterion to exclude injectivity axioms for some inductive types. The issue (as also mentioned in that Agda thread) is that the parameters of an inductive type are excluded from its universe check. That is, although you can write:
You are forced to write
Note the Injectivity for first type This particular paradox doesn't work with So, in my branch (https://github.com/FStarLang/FStar/tree/nik_attemping_349), I have an SMT encoding patch that omits the injectivity axioms for inductives in case one of its parameters includes a function from a universe that is bigger than the universe of the inductive itself. This excludes the paradox, although you can (correctly) still derive false by assuming injectivity of I'm running a regression test to see what impact this has on existing code. Comments most welcome. |
Update: At least in the F* repo, no code regressed. |
I'm a little late on this thread but I'm a bit puzzled about the parameter vs indexes thing in F*. type vector (a:Type) : nat -> Type =
| Nil : vector a 0
| Cons: hd:a -> n:nat -> vector a n -> vector a (n + 1) I would expect the encoding of this type to acknowledge that
Or maybe in a more straightforward fashion
Regarding the paradoxical inductive, I agree with @nikswamy that you have to consider the two "versions" of the inductive, whether you take the function between universes as an index or a parameter.
shouldn't allow you to derive injectivity (after all, it is just a weakening of unit where for some reason we decided to carry around a phantom type) and the encoding should just not provide anything about the parameter. I have the impression it should probably be fine to have the following encoding of inversion for
|
That's a good suggestion Kenji ... to exclude injectivity for all parameters, period. I'm trying it now. |
Ok, that doesn't work ... many regressions. Aseem and I considered this on Friday, but rejected it. This is very intimately related with #65. We might be able to fix them together, some day. More soon. |
Closing this for now since we have fixed this paradox. There could be a potential better fix some day related to #65. If we get to that, let's reopen this issue. |
F* unfortunately still includes injective type formers, although these are known to be inconsistent (and anti-classical). I've ported an inconsistency proof from Lean (https://gist.github.com/leodemoura/0c88341bb585bf9a72e6) to
paradoxes/InjectiveTypeFormers.fst
.The text was updated successfully, but these errors were encountered: