-
Notifications
You must be signed in to change notification settings - Fork 406
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
Superfluous parentheses can inhibit structural recursion #2810
Comments
I ran into this issues a few weeks ago as well, while helping some user. Mostly a guess at this point, so jumping in here just for learning, but probably at this line:
the |
I think that would work to recognize this application, but this is in the context of something that is transforming the expression, so you shouldn't throw away any mdata except the |
Yes, I’d expect a annoyingly special |
Let me give this a shot. I am supposed to work on that code soon anyways, so it’s a good learning experience. |
This didn't work before ``` def f (n : Nat) : Nat := match n with | 0 => 0 | n + 1 => (f) n ``` because the `RecApp` metadata marker gets in the way. More practical, such code seems to be produced when using `rw` or `simp` in recursive theorems. This creates variants of the `Expr.app`-decomposing functions that look through that annotation and uses it in a few neuralgic points in the structural recursion code. Test case is included. Fixes #2810.
This didn't work before ``` def f (n : Nat) : Nat := match n with | 0 => 0 | n + 1 => (f) n ``` because the `RecApp` metadata marker gets in the way. More practical, such code seems to be produced when using `rw` or `simp` in recursive theorems. This creates variants of the `Expr.app`-decomposing functions that look through that annotation and uses it in a few neuralgic points in the structural recursion code. Test case is included. Fixes #2810.
This didn't work before ``` def f (n : Nat) : Nat := match n with | 0 => 0 | n + 1 => (f) n ``` because the `RecApp` metadata marker gets in the way. More practical, such code seems to be produced when using `rw` or `simp` in recursive theorems. We can fix the issue by storing the `.mdata` not around the full application expression, but rather around the inner `.const`. This way, `Expr.withApp` and similar traversals work without without issue. While I’m at it: So far only `WellFounded` was actually making use of this. Now (unlike before) ``` def f (n : Nat) : Nat := match n with | 0 => 0 | n + 1 => f (n + 1) ``` will show the error with squiggly lines under `f (n + 1)`. Test case is included. Fixes #2810.
This didn't work before ``` def f (n : Nat) : Nat := match n with | 0 => 0 | n + 1 => (f) n ``` because the `RecApp` metadata marker gets in the way. More practically relevant, such code is to be produced when using `rw` or `simp` in recursive theorems (see included test case). We can fix this by preprocessing the definitions and floating the `.mdata` marker out of applications. For structural recursion, there already exists a `preprocess` function; this now also floats out `.mdata` markers. For well-founded recursion, this introduces an analogous `preprocess` function. Fixes #2810. One test case output changes: With the `.mdata` out of the way, we get a different error message. Seems fine. Alternative approaches are: * Leaving the `.mdata` marker where it is, and looking around it. Tried in #2813, but not nice (many many places where `withApp` etc. need to be adjusted). * Moving the `.mdata` _inside_ the application, so that `withApp` still works. Tried in #2814. Also not nice, the invariant that the `.mdata` is around the `.const` is tedious to maintain.
This didn't work before ``` def f (n : Nat) : Nat := match n with | 0 => 0 | n + 1 => (f) n ``` because the `RecApp` metadata marker gets in the way. More practically relevant, such code is to be produced when using `rw` or `simp` in recursive theorems (see included test case). We can fix this by preprocessing the definitions and floating the `.mdata` marker out of applications. For structural recursion, there already exists a `preprocess` function; this now also floats out `.mdata` markers. For well-founded recursion, this introduces an analogous `preprocess` function. Fixes #2810. One test case output changes: With the `.mdata` out of the way, we get a different error message. Seems fine. Alternative approaches are: * Leaving the `.mdata` marker where it is, and looking around it. Tried in #2813, but not nice (many many places where `withApp` etc. need to be adjusted). * Moving the `.mdata` _inside_ the application, so that `withApp` still works. Tried in #2814. Also not nice, the invariant that the `.mdata` is around the `.const` is tedious to maintain.
This didn't work before ``` def f (n : Nat) : Nat := match n with | 0 => 0 | n + 1 => (f) n ``` because the `RecApp` metadata marker gets in the way. More practically relevant, such code is to be produced when using `rw` or `simp` in recursive theorems (see included test case). We can fix this by preprocessing the definitions and floating the `.mdata` marker out of applications. For structural recursion, there already exists a `preprocess` function; this now also floats out `.mdata` markers. For well-founded recursion, this introduces an analogous `preprocess` function. Fixes #2810. One test case output changes: With the `.mdata` out of the way, we get a different error message. Seems fine. Alternative approaches are: * Leaving the `.mdata` marker where it is, and looking around it. Tried in #2813, but not nice (many many places where `withApp` etc. need to be adjusted). * Moving the `.mdata` _inside_ the application, so that `withApp` still works. Tried in #2814. Also not nice, the invariant that the `.mdata` is around the `.const` is tedious to maintain.
This didn't work before ``` def f (n : Nat) : Nat := match n with | 0 => 0 | n + 1 => (f) n ``` because the `RecApp` metadata marker gets in the way. More practically relevant, such code is to be produced when using `rw` or `simp` in recursive theorems (see included test case). We can fix this by preprocessing the definitions and floating the `.mdata` marker out of applications. For structural recursion, there already exists a `preprocess` function; this now also floats out `.mdata` markers. For well-founded recursion, this introduces an analogous `preprocess` function. Fixes #2810. One test case output changes: With the `.mdata` out of the way, we get a different error message. Seems fine. Alternative approaches are: * Leaving the `.mdata` marker where it is, and looking around it. Tried in #2813, but not nice (many many places where `withApp` etc. need to be adjusted). * Moving the `.mdata` _inside_ the application, so that `withApp` still works. Tried in #2814. Also not nice, the invariant that the `.mdata` is around the `.const` is tedious to maintain.
Prerequisites
Description
When additional parentheses are inserted around a function, this can prevent structural recursion from succeeding.
Simple example:
With the parentheses, "structural recursion cannot be used." Replacing
(f) n
withf n
makes it succeed. Looking at the terms(f) n
andf n
, the difference is whethern
is included within the recApp metadata expression.This behavior indirectly appeared in a Zulip question when trying to make use of structural recursion within a theorem. This is a minified example:
Replacing
rw [thm]
withrw [thm n]
makes structural recursion succeed -- the terms are identical except for whethern
is included within a recApp metadata expression. Replacingrw [thm]
bysimp only [thm]
also makes it succeed -- in this casesimp
does not create an appRec metadata expression.Context
Zulip discussion
Versions
leanprover/lean4:v4.3.0-rc1
Impact
Add 👍 to issues you consider important. If others are impacted by this issue, please ask them to add 👍 to it.
The text was updated successfully, but these errors were encountered: