-
Notifications
You must be signed in to change notification settings - Fork 32
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
Proposal for unifying the syntax for parameters and indices of inductive types #60
base: master
Are you sure you want to change the base?
Proposal for unifying the syntax for parameters and indices of inductive types #60
Conversation
| cons : A -> list A -> list A. | ||
|
||
Inductive list : forall (A : Type), Type := | ||
| nil : list A |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is A
bound here?
|
||
Inductive list : forall (A : Type), Type := | ||
| nil : forall A, list A | ||
| cons : forall A, A -> list A -> list A. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one and the Inductive list := ...
one at the end make sense IMO, but the ones were only some of the constructors get the forall
and the ones where A
is both on the left of the :
and as a forall
in a constructor don't.
This is similar to definitions: if I do Definition foo (x:bla) : nat := fun x => 0
I get an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is the remark "For clarity of scoping, one may also continue to impose that a variable occurring after the :
cannot be used in the type of constructors."
So we're replacing a trivial criterion with a very complex one which will need to live in the kernel despite not having any model, while at the same time preventing the user to explicitly classify the arguments because some algorithm said so? Looks like a great idea to me 🐊 |
At the high level:
|
@ppedrot I'm not following. Is there a proposal to change something in the kernel here? Surely deciding which parameters are uniform is the job of elaboration, but the kernel representation shouldn't need to change right? |
That's not all the proposal contains |
Obviously you need to change the kernel. Currently the inductive representation is very strict, such a CEP would make it much more complex, so the typing rules of inductive types need to account for that. And that in turn affects guard condition. I am not even talking about horrors with |
This part is actually an old remark of Christine which is made possible with recursively non-uniform parameters and that I'm just forwarding. More generally, parameters are not needed per se. They optimize the representation of indices that are uniform. The remark of Christine is also only one part of the proposal. Its model is the one of inductive families (what proposed Christine can already be interpreted today by moving the parameters of a type that are not common to all types of the block to indices [Added: up to the argument counting for the size of the universe in which the inductive type lives]).
The model is unchanged. Christine's proposal omitted, it differs at worst from a permutation of the arguments. Moreover, I would not call the current model simple per se (isn't it more that we are used to it?). A model which does not distinguish between parameters and indices could arguably be called simpler. See e.g. the related stack overflow question. Also, I would say that a model where you can set independently the name and implicit status of the parameters of constructors and types could arguably be called simpler. It is strange per se that you cannot govern the status of all arguments at definition time. [Added]
Already today, users have not full control on the classification as they cannot force a parameter to be considered as recursively non-uniform. Giving full control to the user on the classification is a good idea per se though and one would have to invent a syntax for it. |
Something like this is very welcome. The current syntax is not ideal (and often confusing). I don't know whether it should all be purely inferred, as here, or if there ought to be purely specified syntactically. Probably you'd want the inference algorithm to be more precise to make sure that you can explain its failures (in error messages). And to make sure that we don't have data types unexpectedly (and inexplicably) jumping universe level. |
This is not quite true. AFAIK in the Set model, parameters are handled as real lambda abstractions and mutual blocks only quantify over their indices. In particular, structural typing à la coq/coq#5293 makes sense for parameters, but not for indices.
The very fact you had to add this mention this is not precisely going to relax me. The MetaCoq people have been unearthing forbidden knowledge like breakage of SR with a clever use of inductive types. Adding even more complexity to the mix cannot go well if you don't justify a bit more the validity of the approach, e.g. producing a convincing sketch of model, or even better, a MetaCoq proof. I am afraid that authority arguments from hearsay from the 90's shouldn't be considered valid. Also, mere logical validity is a thing, but you also need to consider at least some handwaving argument for decidability of type-checking, SR and all the syntactic whatnot we care about. Given that's it's probably already wrong with the current situation this does not look good. (As usual you should also consider consequences for upper layers. First thing that comes to my mind is the question of the type of the auto-generated recursor for such generalized types.)
It's not simple, and we should strive to make it simpler. I am not against a fancy user-facing mechanism like you propose, but it should be elaborated to something easy to check.
This is not true : https://coq.inria.fr/refman/language/core/inductive.html#coq:flag.Uniform-Inductive-Parameters. |
You misread the negation, that can force a parameter to be uniform but cannot force to be non uniform. |
Are you saying that the kernel will generalize the type in your back to a uniform one even though you explicitly asked not to by putting said parameter after the pipe? This looks like a bug to me... |
That's just an incorrect interpretation of putting the parameters after the pipe.
and when the flag is unset we get the usual automatic discrimination between uniform and non uniform. |
To be clear, I'm not claiming that my proposal is authoritative nor that the old proposition of Christine is. As I insisted in the text, it is a proposal. I did not make a formal proof of whatever about it and I'd be precisely glad to have an opinion of MetaCoq people. In particular, I'm not opposed to the idea that MetaCoq proofs are produced, well on the contrary. If I'm proposing this CEP, it is because I think it is an idea which makes sense and that it is worth to ponder different approaches. The complexity of the Metacoq formalization is an important criterion but the practicability is too. At this point of the discussion, it is not clear to me that the changes discussed here would be more difficult to MetaCoqize than the current situation. As you suggest below, it is not to be excluded that it could be elaborated to something easy to check.
I'm unsure about what you exactly have in mind. You are probably not talking about negative records with eta since negative records don't have indices. But what happens in the Set model is important, yes.
What the MetaCoq formalization uncovers is indeed extremely valuable. MetaCoq is a very important project.
Yes, the question of the upper layers is important. Here, the types of elimination predicates would be unchanged. However, as for the order of arguments, this is another situation showing that the order chosen by default is not necessarily optimal (*). We can still keep the existing order by compatibility though. (*) An example which does not fit well already with the current convention is the scheme for rewriting from right to left:
Sure. |
coq/coq#5293 is only tangentially about primitive records. What the author was asking for was (a subset of) local inductive blocks, which is what the Set model provides. In such a model, we have e.g.
because parameters are implemented as standard λ-abstractions. Since the above inductive type doesn't mention its parameter argument, we get this conversion for free by mere application of a β-rule. More generally, in this model conversion of inductive types is essentially given by pointwise conversion of the type of the constructors of the block. This does not make sense when interpreting parameters as indices. |
Hum, frankly this seems a lot of complexity (mostly in the kernel) for little gain. Moreover, parameters, nu-parameters and indexes are different. We recently got a syntax to remove the last ambiguity by putting nu-parameters after Finally, I find the current order of arguments quite natural if you you have a background in functional programming. What does not vary in a rec function, you pass it first, since it ease partial application. What changes you pass it last, eg you use the function keyword (in OCaml). This practice transposes well to Coq's inductives, so it's a bit easier to remember/learn it for a class of users, IMO. |
As mentioned that's a misunderstanding, the parameters after the |
May I rephrase your remark into the fact that for the two definitions
and
|
Yes, that's one way to see it. It's not only about params not appearing in |
Is there a real use case for interleaving params and nu-params? |
The proposal is probably badly written if it gives so much the impression of complexity, but there are actually four independent parts in it: The first two parts do not change the kernel:
The last two parts do change the kernel (but only slightly):
|
I think the symmetrization of patterns was a good choice, starting with the ability to use the same notations in patterns than in terms. Moreover, parameters are currently supposed to be replaced by Idem for the return clause, we force the parameters to be I don't think that this would be more complicated to explain than the current situation. But I agree that it is also about pedagogy, and we need to experiment to know what is the most natural way to explain things. |
If an index comes first, can subsequent parameters or nu-parameters depend on it? |
Typability implies that a parameter cannot depend on a true index (i.e. an index which could not be classified itself as a parameter). Similarly, typability implies that a uniform parameter cannot depend on a (truly) non-uniform parameter. |
So I don't see what is the point of allowing an arbitrary order.
IMO 1 is sound, 2 is reasonable (assuming this inference works in practice), 3 is just not worth it (and seems the point which changes the kernel). |
On another point, I think that being allowed to repeat parameters in constructors just for the sake of setting their implicit status is an x-y problem. According to my experience the status of parameters should be the same all over, with a few exceptions, eg one may want to make |
But if the dependencies between arguments have to respect the indices > nu-parameter > parameter order, these does not mean that two arguments have necessarily to be dependent the one of the other (it can be a graph). For instance, currently, I cannot define
|
Yes, the change is not needed per se to set names or implicit arguments of constructors ( Personally, 1 and 3 are the ones I'd like to have. I'm not particularly advocating for 2, but here is nevertheless an example where 2 might be useful... The library
Imagine I'd like the type to formally be
|
And to go further, I don't see why to force users to have headache on how to define
|
Why should any of the two argument be a parameter? To me |
Then I believe that we agree, i.e. we could try to defend a user view where there are only "indices". |
Actually, I wonder where parameters really matter in the kernel? Could it be that the status of parameter is used only for the nested positivity condition and the nested guard condition (which seem by the way both more restrictive than in Agda)? As said by @ppedrot, parameters are important in the upper layers though:
|
Parameters matter a lot for matches |
Right, they matter more than just for the inference of the If all parameters started to be treated like indices in [Digression: These equalities could be recovered with a "small inversion"-like generalisation though. More generally, there are actually more definitional equalities to expect between arguments of the type and arguments of the constructor than just the parameters. This morally applies to all arguments that are fresh variables in the type of a constructor. So, at some time, typing of Anyway, this goes too far from the initial idea. Maybe MetaCoq may like at some time to consider dropping parameters in the metatheory of inductive types and compensating with hard-wired definitional equalities in the typing of So, my current summary about this CEP is: would we like to simplify the user model about inductive types, as suggested in the examples of |
I feel inference of parameters would be more confusing, because then you have to run the inference in your head to understand how to use match. I support the part about having parameters on individual inductives instead of shared across a block, but not the rest of the proposal. |
You can also count on [If you are talking about the current constraint of using |
This is a proposal in passing for more flexibility in the concrete syntax of inductive types.
Rendered here.