Skip to content
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

RFC: termination_by structurally x #3909

Closed
nomeata opened this issue Apr 15, 2024 · 4 comments · Fixed by #4542
Closed

RFC: termination_by structurally x #3909

nomeata opened this issue Apr 15, 2024 · 4 comments · Fixed by #4542
Labels
RFC Request for comments

Comments

@nomeata
Copy link
Collaborator

nomeata commented Apr 15, 2024

Proposal

Right now if the user writes a recursive function without annotation, Lean tries

  • structural recursion on each argument
  • well-founded recursion with GuessLex

If the user wants to be explicit about well-founded recursion, they can use termination_by x. But they have no way of indicating that they want to use structural recursion on a specific argument.

Right now the above search procedure is not slow, so the need isn’t high, but once we have structural recursion on mutually recursive functions, the first step might consider many combinations, and it would be good if the user can just declare their intent.

Furthermore, if the user can be specific, they get a less noisy error message when the derecursifying fails.

Initial proposal for the syntax is

termination_by structurally x      -- if x is bound before the colon
termination_by structurally x => x -- if x is bound after the colon

in analogy to the existing termination_by. This way, no new “definition trailing keyword” is introduced.

It can also be extended to more variants in the future, such as termination_by tail-recursion (which isn’t really “termination”, sigh.)

Once we have this, then termination_by? should not force well-founded recursion and should, if lean detects structural recursion, suggest the corresponding termination_by structurally … annotation.

Community Feedback

(none yet)

Impact

Add 👍 to issues you consider important. If others benefit from the changes in this proposal being added, please ask them to add 👍 to it.

@nomeata nomeata added the RFC Request for comments label Apr 15, 2024
@nomeata
Copy link
Collaborator Author

nomeata commented Apr 15, 2024

I am happy to hear alternative syntax ideas; the termination_by structurally x suggested above is somewhat clunky.

@digama0
Copy link
Collaborator

digama0 commented Apr 15, 2024

I think it should be styled closer to options in tactic syntax, e.g. termination_by (method := structural). This also gives a bit more freedom to tweak the syntax without clashing with either the expr or ident parser.

@b-mehta
Copy link
Contributor

b-mehta commented Jun 26, 2024

I can't comment on the implementation here, but the proposal is something I would absolutely find valuable. Can we, however, make sure that the expected behaviour is documented somewhere?

@nomeata
Copy link
Collaborator Author

nomeata commented Jun 26, 2024

Yes, of course! I hope that by the end of the year there will be an amazing reference manual that’s a joy to keep updated as I add features. Until then we are a bit in a limbo. But that’s for the reminder to at least keep the docstring on termination_by up-to-date (docstring extended in c3398e3).

github-merge-queue bot pushed a commit that referenced this issue Jul 1, 2024
This implements the `termination_by structural` syntax proposed in
#3909.

I went with `termination_by structural` over, say,
`termination_by (config := {method := .structural})` mainly because it
was
easier to get going (otherwise I’d have to look into how to define
recursive
parsers, as `Parser.config` depends on `term` and `termination_by` is
part of
term. But also because I find it more ergonomic and aesthetic as a user.
But syntax can still change.

The `termination_by?` syntax will no longer force well-founded
recursion,
and instead the inferred `termination_by structurally` annotation will
be shown
if structural termination is possible.

While I was it, this fixes #4546 the easy way (log errors about but
otherwise
ignore incomplete `termination_by` sets for mutual recursion). Maybe we
get
multiple replacements (#4551), but even then this this good behavior.

Involves a bit of shuffling around `TerimationHints` (now validated for
a
clique already by `PreDefinition.main`) and `TerminationArguments` (now
lifted
out of the `WF` namespace, and a bit simplified).

Fixes #3909

---------

Co-authored-by: Richard Kiss <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
RFC Request for comments
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants