Inherit implicit arguments in coercions to Funclass (fixes/grants #5527)#11327
Inherit implicit arguments in coercions to Funclass (fixes/grants #5527)#11327herbelin wants to merge 8 commits intorocq-prover:masterfrom
Conversation
99cbb4a to
a3784e3
Compare
a3784e3 to
d45f702
Compare
|
Report on the failures: the compatibility test works pretty well. Only the case where a second coercion to Funclass is applicable fails to be detected. This happens in two cases:
Here is for the record a simplified example of what |
|
Yet another question. If I have: should I accept Maybe, @pi8027, did you already encounter such issues? |
|
I've mixed feelings about this feature, especially in his cost/benefit. The benefits are totally unclear to me. In particular quantifying in the middle of a spine of arrows is weird, it seems more natural to put the type of the term acting as a coercion in a prenex form, i.e. put the implicit argument before the term being casted. To me the coercion is a "technical term" (that the user is not even supposed to see) so requiring it to have a specific shape does not seem an hard requirement (we already require it to have some other properties for example). |
|
@gares: @tchajed gave an example at #5527 and there are examples in Iris, UniMath, suspectingly in mathcomp too. You are basically liable to have implicit arguments in a coercion to See for instance a comment mentioning this issue in Iris' file ofe.v: |
|
Yes, @gares, from a benefits perspective this feature would be awesome, though I can't comment on how much complexity it adds. The issue is basically that you effectively can't have Funclass coercions to polymorphic functions; it actually exposes that you're using a coercion because you need these |
|
@gares: if you want examples in MathComp, look for the warning |
pretyping/pretyping.ml
Outdated
| warn_tolerance_no_coercion_implicit_argument ?loc (!!env,sigma,coe); | ||
| x | ||
| with e when CErrors.noncritical e -> | ||
| raise e' |
There was a problem hiding this comment.
Instead of doing this try-with dance, you should return an algebraic type in f, catching the exception there. Using exceptions for control flow is a recipe for a disaster.
There was a problem hiding this comment.
Is the risk that warn itself raises an error?
I can certainly use a sum type instead, but this is anyway supposed to be temporary and I fail to see how much it really matters here, even though I'm ready to follow recommended common practices which improve our synergy.
There was a problem hiding this comment.
@ppedrot: I experimented using a sum type. It is actually nicer than what I had thought!
|
@gares, your suggestion to put the quantification in prenex position works, but does not survive composition. |
IMO, declarations of implicit coercions should be independent of |
Would it be ok that the warning is temporary and that taking implicit arguments of coercions to
That's right. One could otherwise give to: the meaning of declaring |
d45f702 to
d1be1a4
Compare
pretyping/pretyping.ml
Outdated
| | Some (coe,_) -> | ||
| let c',rest',some_change = insert_impargs ?loc impls c rest in | ||
| if not some_change then f c rest else | ||
| let g c rest = try Inl (f c rest) with e when CErrors.noncritical e -> Inr e in |
There was a problem hiding this comment.
Please avoid generic catch-all of exceptions.
There was a problem hiding this comment.
Sorry, I did not get it. What is your suggestion?
There was a problem hiding this comment.
As @ppedrot suggested before f should not raise and instead return an algebraic type; the code indeed looks pretty hard to reason as calls to user_err are later absorbed.
There was a problem hiding this comment.
Moreover the reraise is likely incorrect below, as in it loses information. That should not matter for Coq, but unfortunately that may not be the case.
There was a problem hiding this comment.
As @ppedrot suggested before f should not raise and instead return an algebraic type
I don't see how I can avoid f to raise an exception. f is calling unify, pretype, all kinds of function which possibly raise an exception w/o having control on where it is raised.
as in it loses information
You mean information of the trace?
By the way, I meant reraising e' not e. Changing.
There was a problem hiding this comment.
I don't see how I can avoid
fto raise an exception.fis callingunify,pretype, all kinds of function which possibly raise an exception w/o having control on where it is raised.
Do we have an specification of what these functions can raise? Indeed they should not raise except on error, and if there is an error there why we absorb it? IMHO we really have a mess in the codebase. I cannot understand for example why here all errors are actually absorbed, that seems wrong in a few cases, like for example a missing lib by Coqlib etc... Yeah our notion of "recoverable error" is pretty ill-defined.
I know that is it not easy to fix this, but at least IMO in new code the try ... with ... block should be pushed to the inner boundaries so they act as wrappers of the raising functions and turn the caught exception into something sensible.
You mean information of the trace?
Of the trace and anything else users attached to it using our dangerous Exnifo API.
There was a problem hiding this comment.
Do we have an specification of what these functions can raise?
You know how helpful is OCaml to inform about side effects!
In any case, this could be a catch of precatchable_exception instead of noncritical but I'd bet that this would not make a difference.
Are you suggesting that we should pass not only states but exceptions in purely functional style?
There was a problem hiding this comment.
if there is an error there why we absorb it
It's done that way to implement the compatibility mode.
IMO this is the wrong way to work, if we want the PR's feature we should put an option to disable it and deprecate the option. Then we don't need to catch exceptions here.
There was a problem hiding this comment.
Having a warning with a location is useful to upgrade. Then, we could do an automatic translation, the same way the python script replaced automatically references to deprecated aliases in 8.9. An option is possible in parallel.
There was a problem hiding this comment.
@ejgallego: I added an Exninfo.capture to not "lose information". Otherwise, I don't know how I can reasonably avoid catching all non-critical exceptions. As the code is written and as OCaml is designed, I have no precise idea of what exceptions typing functions exactly raise. How to control this would go well beyond the scope of the PR (starting with a careful documentation of these functions, eventually ensuring, e.g., that a typing function raises only PretypeError!?).
In any case, in a context of extensibility of exceptions, we will certainly have at some point to clarify whether we characterize exceptions positively (i.e. knowing the list of exceptions a function can raise) or negatively (i.e. knowing the list of exceptions a function should not raise).
4adb443 to
c59b72d
Compare
|
The "needs: rebase" label was set more than 30 days ago. If the PR is not rebased in 30 days, it will be automatically closed. |
|
This PR was not rebased after 30 days despite the warning, it is now closed. |
… to Funclass. Inherit also interpretation scopes of the coercion.
…funclass coercions.
c59b72d to
6e2aecb
Compare
I thought extra scopes were also used in the case of polymorphic functions which might be instantiated with arrow types. |
|
Summary of my position after the Coq call: I suggested the possibilities of:
|
|
The "needs: rebase" label was set more than 30 days ago. If the PR is not rebased in 30 days, it will be automatically closed. |
|
This PR was not rebased after 30 days despite the warning, it is now closed. |
Kind: Enhancement
Fixes / closes #5527
The PR includes some commits from #11326 (merged).
This is a proposal so as to inherit implicit arguments in the presence of coercions to Funclass.
For elaboration, we work at the level of
pretyping.mlto insert implicit arguments whenever a coercion to Funclass is used. In particular, we need to moveimpargs.mlinpretypingso that it can be called fromcoercion.ml. @ejgallego: are you ok? (Note that it would be natural to mergeimpargs.mlandarguments_renaming.ml. The latter is inpretypingso that it can be called intyping.ml. This is a second reason to moveimpargs.mlintopretyping, even if it is bit disappointing to see that implicit arguments impact typing.)TODO: understand better inheritance of interpretation scopes. With this PR, interpretation scopes are inherited (for printing) from the coercion scopes. Before, the "extra scopes" of the main argument of the coercion were used instead (for printing). As far as I understand, the point of "extra scopes" is to reflect the scopes of the coercions to Funclass, but that would need to be checked. (Eventually, the "extra scopes" hack could also be removed.) Extra scopes at interning are unchanged.
Added: To improve compatibilities, a temporary fallback on discarding implicit arguments has been implemented, together with a warning. It fails to detect cases where a second coercion to Funclass can (unexpectedly) be applied in a row.