Zulip Chat Archive
Stream: mathlib4
Topic: The plan to remove induction'
Jeremy Tan (Mar 22 2025 at 06:10):
Jeremy Tan (Mar 22 2025 at 08:29):
#23211 is the first big automated commit in my plan to remove induction'. It targets mainly Nat induction, which by far is the most common target of induction' in current mathlib
Peter Nelson (Mar 22 2025 at 23:23):
Is there a clear consensus that induction' should be removed?
Jeremy Tan (Mar 22 2025 at 23:47):
Yes; see the other thread about cases'
Jeremy Tan (Mar 22 2025 at 23:50):
And #lean4 > To replace `induction' h : f x` @ 💬
Jeremy Tan (Mar 22 2025 at 23:52):
(now that the missing functionality has been added to plain induction and is available in current mathlib I am free to go remove induction')
Jeremy Tan (Mar 23 2025 at 01:35):
I acknowledge that not all the stated instances have been removed, but as 400+ of 1000 instances are removed by #23211 I'd really want to get this merged quickly so I can go again without suffering rot
Peter Nelson (Mar 23 2025 at 11:32):
The way I would read that discussion is that a particular obstacle to its removal was identified, and that now that obstacle is gone. But I wouldn’t call that a clear consensus.
Peter Nelson (Mar 23 2025 at 11:35):
induction' isn’t the same as cases', because there is no rcases or obtain-like syntax to replace it with.
Eric Wieser (Mar 23 2025 at 12:21):
Doesn't the fact that the PR was fully automated with a script mean that it's trivial to deal with rot? You just git reset --hard origin/master and rerun the script.
Peter Nelson (Mar 23 2025 at 13:10):
The thing that slightly concerns me here is that removing (or discouraging) induction' is pushing users towards equation-compiler-like syntax with | and =>, which is a departure from the dots and indents of the rest of tactic mode. While I now use induction myself, I think that induction' is often better for new users finding their feet, and unlike with the removal of cases', these users don't have alternatives.
I'm not saying the change shouldn't be made, but it feels like this is something a single user is pushing for, rather than where there is a clear statement from the maintainers that this change is intended.
Jeremy Tan (Mar 26 2025 at 01:54):
#23324 deprimes Data.List
Jeremy Tan (Mar 26 2025 at 01:55):
Peter Nelson said:
I'm not saying the change shouldn't be made, but it feels like this is something a single user is pushing for, rather than where there is a clear statement from the maintainers that this change is intended.
There is a clear approval for this change: #lean4 > To replace `induction' h : f x` @ 💬
Jeremy Tan (Mar 26 2025 at 02:03):
The situation with induction' and induction is like Python 2 and Python 3. All the major players in the software industry had deprecated Python 2 and moved on but there were a number of users irrationally clinging on to Python 2
Jeremy Tan (Mar 26 2025 at 02:16):
Peter Nelson said:
The thing that slightly concerns me here is that removing (or discouraging)
induction'is pushing users towards equation-compiler-like syntax with|and=>, which is a departure from the dots and indents of the rest of tactic mode.
Diversity of syntax is a Good Thing for new users – it makes code visually more appealing and prevents misconceptions about tactic mode. | and => will help them learn the equation compiler
Johan Commelin (Mar 26 2025 at 02:24):
I don't see the "clear approval".
I think these refactors should be explored, but no decision has been made.
Jeremy Tan (Mar 26 2025 at 02:27):
@Jireh Loreaux left a comment on my last merged depriming PR (#22533): https://github.com/leanprover-community/mathlib4/pull/22533#discussion_r2007860604
I'm glad this is getting fixed. I think this is a particularly egregious example of the lack of explicit structure in
induction'
Can we agree that uses of induction' with five or more introduced variables are "egregious" and should be deprimed?
Jeremy Tan (Mar 26 2025 at 02:31):
(And if zero variables are introduced, it can always be replaced straight up with induction)
Jeremy Tan (Mar 26 2025 at 09:20):
Jeremy Tan (Mar 26 2025 at 09:23):
I beefed up my script. Now it leaves less than 450 instances of induction'
Jeremy Tan (Mar 26 2025 at 10:58):
(to be precise, 430)
Peter Nelson (Mar 26 2025 at 11:11):
@Jeremy Tan , I think I agree that removing induction' makes sense. But you are being impatient, and glibly dismissive of any resistance. Often people that act this way are in fact trying to push for something bad.
Jeremy Tan (Mar 26 2025 at 11:39):
Anyone trying to push through a large change has to be impatient to some extent – has to address the concerns of the resistance as far as they can, but ignore the remainder. Otherwise they will be quickly defeated
Jeremy Tan (Mar 26 2025 at 11:40):
I have addressed your concerns as far as I can here, and #23211 is now error-free
Peter Nelson (Mar 26 2025 at 13:13):
I think that Nat is one of the more defensible settings for the use of induction'.
In contrast to structural examples with a ton of introduced variables, induction on the natural numbers is intuitive to any mathematician without the concept of ‘deconstructing’ some n, and the induction' syntax is more sympathetic to that perspective.
Peter Nelson (Mar 26 2025 at 13:26):
Maybe tackling the examples with large numbers of variables, rather than Nat, would be a natural place to start?
Jireh Loreaux (Mar 26 2025 at 14:22):
Jeremy, my comment was specifcally about that use of induction' with many branches.
In general, I personally (not a mandate from the maintainers) prefer the extra structure with the induction tactic, even if it is slightly more verbose, especially because we have a code action for it. However, from the other thread, it was clear that removing induction' was not as desirable in all situations as removing cases' (thanks for doing that!). The reason I merged that one PR of yours about induction' is that all of those replacements did not seem to be relevant to the condition mentioned in the other thread. (I have not had time to review your other PRs on this topic, so I don't know about those.)
Jeremy Tan (Mar 26 2025 at 14:27):
I'm going to make a PR (or rather overwrite an existing PR) removing those induction' with five or more named variables – see https://github.com/leanprover-community/mathlib4/compare/master...option2
Jeremy Tan (Mar 26 2025 at 14:27):
I may later extend that to four variables
Jireh Loreaux (Mar 26 2025 at 14:28):
okay, but why not wait for some consensus on how to proceed? Instead of jumping the gun, first determine what the community wants.
Jeremy Tan (Mar 26 2025 at 14:29):
Only @Peter Nelson has given his thoughts and I'm not sure the community has any opinions on this
Jireh Loreaux (Mar 26 2025 at 14:30):
Johan Commelin said:
I don't see the "clear approval".
I think these refactors should be explored, but no decision has been made.
This is the message that should make you stop and think: "hmmm, maybe I should wait on this."
Jeremy Tan (Mar 26 2025 at 14:36):
But I might have to wait forever on that
Edward van de Meent (Mar 26 2025 at 14:37):
yes. and that's ok
Jireh Loreaux (Mar 26 2025 at 14:39):
Jeremy, I'm taking steps in the other thread now to see if we can come to a decision. But indeed, sometimes you (or even me!) have to wait indefinitely for certain things.
(For instance, I would love to see a global PartialOrder â„‚ instance, but that hasn't won enough approval in the past to warrant the change.)
Jeremy Tan (Mar 26 2025 at 16:44):
Peter Nelson said:
Maybe tackling the examples with large numbers of variables, rather than
Nat, would be a natural place to start?
Eric Wieser (Mar 26 2025 at 17:20):
Searching that PR for | h_ flags a number of induction principles whose arguments should be renamed (in a separate PR)
Aaron Liu (Mar 26 2025 at 17:48):
Eric Wieser said:
Searching that PR for
| h_flags a number of induction principles whose arguments should be renamed (in a separate PR)
I have a plan to go through all induction principles in mathlib by hand and rename them
Jeremy Tan (Mar 27 2025 at 03:23):
Eric Wieser said:
Searching that PR for
| h_flags a number of induction principles whose arguments should be renamed (in a separate PR)
Kim Morrison (Mar 27 2025 at 04:46):
@Jeremy Tan, if you're waiting on decisions here, let me invite you to join in our quest to reduce the use of erw in Mathlib.
The goal isn't to just replace it with other tactics or rely on unification to blast through the defeq problems, but instead to improve simp (better normal forms, better confluence) lemmas to avoid needing erw in the first place. There are >1000 erw still in the library. Have a look at recent PRs with erw in the title if you'd like inspiration.
(Of course, feel free to do anything else --- it just occurred to me that this is a project you might enjoy!)
Jeremy Tan (Apr 05 2025 at 03:51):
Could we support syntax like
cases x using someInductionOn with a b c
induction x using someInductionOn with a b c
just when someInductionOn has only one branch with new variables a b c? @Kyle Miller
Jeremy Tan (Apr 05 2025 at 03:52):
@Peter Nelson Would the above proposal be a suitable replacement for single-branch cases'/induction'?
Kyle Miller (Apr 05 2025 at 04:19):
We can do induction x using someInductionOn with | _ a b c. The problem with omitting | _ is that right after with the syntax is looking for a tactic.
Jeremy Tan (Apr 05 2025 at 04:20):
Peter said here that that "makes the line longer and introduces a lot of functional programming boilerplate"
Jeremy Tan (Apr 05 2025 at 04:21):
In fact the blanked-branch syntax is what Eric put into one of my prior depriming induction PRs
Jeremy Tan (Apr 05 2025 at 04:24):
How about cases1 and induction1?
Jeremy Tan (Apr 05 2025 at 04:53):
Or even
induct x using someInductionOn with a b c
(since induct would be a new tactic, with is not constrained to expect a tactic afterwards)
Edward van de Meent (Apr 05 2025 at 06:13):
I feel like creating a new tactic just to remove another defies the purpose?
Jeremy Tan (Apr 05 2025 at 07:02):
Edward van de Meent said:
I feel like creating a new tactic just to remove another defies the purpose?
Or we could make some new field (e.g. with1) for cases and induction to indicate "there is exactly one branch, here are its variables"
Jeremy Tan (Apr 05 2025 at 07:05):
(i.e. with1 or whatever we decide on cannot be used with with and will error if the inductor has more than one branch)
induction x using someInductionOn with1 a b c
=
induction' x using someInductionOn with a b c
Jeremy Tan (Apr 05 2025 at 07:16):
It must be understood that this is just a nice-looking shorthand for the blanked-branch syntax
Peter Nelson (Apr 05 2025 at 10:25):
Jeremy Tan said:
Peter said here that that "makes the line longer and introduces a lot of functional programming boilerplate"
The specific comment I made was that
cases p with | _ m s => ?_ looks worse than
induction’ p with m s.
I don’t have a strong view on what syntax is used, but in that specific instance, cases looks very clunky
Ruben Van de Velde (Apr 05 2025 at 11:06):
Yeah, that's pretty much the worst case and I wouldn't mind shortening it somehow. I'm not sure I'd add a whole separate tactic for it if it didn't exist yet, though
Eric Wieser (Apr 05 2025 at 11:29):
Ideally obtain or rcases would work here, but it doesn't support the custom eliminators
Peter Nelson (Apr 05 2025 at 12:10):
Is expanding obtain/rcases on the roadmap?
Peter Nelson (Apr 05 2025 at 12:27):
And if it is, what's the hurry to remove induction'?
Ruben Van de Velde (Apr 05 2025 at 12:27):
There is no hurry
Eric Wieser (Apr 05 2025 at 12:29):
I think there's a reasonable argument to start removing induction' where the replacement is obviously more readable, in that it's general cleanup and it identifies the places which are not more readable.
Eric Wieser (Apr 05 2025 at 12:30):
But I think there's an element of Goodhart's law going on here, in that I think this is included in the technical debt counters
Jeremy Tan (Apr 05 2025 at 17:53):
@Eric Wieser I do have #23686 ready for review, fixing more induction branch names (and motives)
Kyle Miller (Apr 05 2025 at 17:58):
What does renaming motives to motive do? I haven't seen any discussion about this.
There aren't any systems that require the motive to be named motive (you can tell it's a motive because the return type has it as the head function). There's an overly-specific pretty printer that looks for an argument named motive, but I've been thinking of fixing that.
I suppose it's nice knowing that an argument is the motive by looking at it, but on the other hand whenever you see some higher-order named argument like (argName := fun a b c => ...), very often it's something motive-like.
Jeremy Tan (Apr 05 2025 at 17:59):
Eric insisted on fixing up the motives in a previous PR on the same topic
Jireh Loreaux (Apr 05 2025 at 17:59):
There was a poll somewhere about this, and the result was motive is the preferred spelling.
Jireh Loreaux (Apr 05 2025 at 17:59):
(as opposed to p or P or whatever)
Jireh Loreaux (Apr 05 2025 at 18:00):
Edward van de Meent (Apr 05 2025 at 18:02):
from the looks of it, you even voted on the polls, Kyle :face_with_open_eyes_and_hand_over_mouth:
Aaron Liu (Apr 05 2025 at 18:04):
I have a pr #23489 that will rename all the motives I can find once I finish it
Kyle Miller (Apr 05 2025 at 18:07):
Thanks! I forgot about the poll.
(This is the core delaborator code that is overly restrictive with what it considers to be a motive argument.)
Edward van de Meent (Apr 05 2025 at 18:14):
the motive argument is just the argument which provides the head symbol for the returntype, right? (this seems to be how the machinery of induction does it?)
Edward van de Meent (Apr 05 2025 at 18:15):
i.e. if you use docs#Lean.Meta.getElimExprInfo you should get the right argument, i think?
Edward van de Meent (Apr 05 2025 at 18:16):
although i guess this does not capture induction with multiple motives
Kyle Miller (Apr 05 2025 at 18:39):
Yes @Edward van de Meent:
Kyle Miller said:
you can tell it's a motive because the return type has it as the head function
Mario Carneiro (Apr 05 2025 at 19:02):
Kyle Miller said:
you can tell it's a motive because the return type has it as the head function
That's not necessarily the case; in mutual recursors there are additional motives which are not the head of the return type
Edward van de Meent (Apr 05 2025 at 19:03):
Indeed
Edward van de Meent said:
although i guess this does not capture induction with multiple motives
Kyle Miller (Apr 05 2025 at 19:05):
I didn't meant that to be an if-and-only-if.
At least the motives all appear in the return types of the minor premises, right? I'm not sure though, maybe you need to look in the arguments of minor premises as well... In any case, multi-motive is a place where it doesn't work to name every motive motive.
Kyle Miller (Apr 05 2025 at 21:55):
lean4#7830 is a prototype testing out the change to the cases/induction syntaxes that I was suggesting.
With this, you can write
cases p with | _ m s
as as shorthand for
cases p with | _ m s => ?_
If you name cases, then you can also write
induction n with | zero | succ n ih
· tac1
· tac2
rather than
induction n with | zero => ?_ | succ n ih => ?_
· tac1
· tac2
It's not possible to write induction n with | _ | _ n ih. Somewhere @Mario Carneiro suggested that cases/induction should support multiple wildcards. Until today, I didn't realize that _ causes the alternative to apply to every remaining pattern. I find this to be unexpected, and I wonder if this should be changed; should _ mean "next remaining case" and have a new * to mean "every remaining case"?
Jeremy Tan (Apr 06 2025 at 01:48):
Kyle Miller said:
With this, you can write
cases p with | _ m sas as shorthand for
cases p with | _ m s => ?_
I would like to see the shorthand I suggested for the one-branch case:
cases p with1 m s
Once again the conditions for using with1 are that there is only one branch and that with is not used
Kyle Miller (Apr 06 2025 at 19:15):
Introducing a new keyword to save three characters doesn't seem like something core Lean would go for.
cases p with | _ m s
cases p with1 m s
Maybe the rcases pattern syntax could accept named constructors in addition to anonymous constructor notation. That could give the alternatives
obtain Prod.mk m s := p
-- or perhaps
obtain mk m s := p
-- or, for short
obtain _ m s := p
(I'm assuming that the rcases system would know about custom cases eliminators. I'm not sure how rcases should accept using clauses. The point of rcases is that it's recursive deconstruction, so it seems to me that it shouldn't be a single top-level using clause.)
Potentially there could be a special pattern to do induction too. It's possible to have something like this work:
obtain induct(_ | ⟨n, ih⟩) := n
It's just something that came to mind, and I'm not sure I'd want to see it implemented. But, it's clear that it could be convenient sometimes:
obtain induct(⟨_|_|n, ih⟩ using Nat.strongRecOn) := n
That's strong induction on n and then immediately doing cases on n into the 0, 1, and n+2 cases.
Mario Carneiro (Apr 06 2025 at 19:18):
one possibility is something like haskell view patterns, like obtain (Nat.strongRecOn => ⟨n, ih⟩) := n. It gets a bit cluttered though, I worry a bit about it turning into something unreadable like ssreflect intro patterns
Kyle Miller (Apr 06 2025 at 19:20):
I worry too, but at least in Lean we get to set the tactic infos, letting people step through intermediate states to some degree; my understanding of ssreflect is that you can only see the before and after state.
Jeremy Tan (Apr 11 2025 at 03:44):
Kyle Miller said:
cases p with | _ m s
OK, I'll be content with this
Jeremy Tan (Sep 05 2025 at 00:19):
Currently open PRs in this direction:
- #29123 (
Data.{*Nat, Int, *Real}) - #29124 (
Data.*Fin*) - #29285 (most of
RingTheory) - #29286 (most of
Algebra) - #29313 (
Data.List)
There are less than 500 uses of induction' left. I would really appreciate it if all these PRs were merged sooner rather than later (all are independent of each other)
Jeremy Tan (Sep 05 2025 at 00:23):
Especially #29313 since most files touched in that PR are at the base of the import web for all mathlib
Jeremy Tan (Sep 05 2025 at 00:40):
@Eric Wieser did you mean to maintainer merge #29123 after I addressed your review comments (I have done so)?
Jeremy Tan (Sep 11 2025 at 08:09):
#29542 removes the last uses of induction' in mathlib, archive and counterexamples
Jeremy Tan (Sep 11 2025 at 08:10):
After this is merged, all that will be left is to add induction' to the deprecated syntax linter
Jeremy Tan (Sep 11 2025 at 11:42):
Jeremy Tan said:
After this is merged, all that will be left is to add
induction'to the deprecated syntax linter
#29548 does this
Jeremy Tan (Sep 11 2025 at 13:41):
/poll Poll for #29548, now that induction' has been completely removed from main mathlib
Yes
No
Kyle Miller (Sep 11 2025 at 17:08):
It would be nice if the deprecation were to come with a "try this" suggestion. I see that the linter is being added without being enabled, so that's less of a concern, but if it ever were enabled by default for downstream projects I think we have some responsibility to smooth the migration.
That's tricky though since induction' is unstructured. At least it could suggest a structure that someone could use to copy in cases from the rest of the proof. For example, induction' n with n ih could suggest
induction n
· sorry
next n ih =>
sorry
for a close analogue to the old version. It could give both that and the where option as well, with more work.
Robin Arnez (Sep 11 2025 at 17:22):
Isn't it easiest to just suggest induction n with | zero | succ n ih?
Kyle Miller (Sep 11 2025 at 17:26):
If it works, then that would be best, but you'll have to work out when to use @ and whether the with variables actually can always be lined up with alternatives.
Eric Wieser (Sep 11 2025 at 17:26):
Where would the try this live? In the tactic itself?
Ruben Van de Velde (Sep 11 2025 at 17:26):
Matching the unstructured list of names to the alternatives? Sounds like a fair bit of engineering that might not be worth it for a deprecation
Eric Wieser (Sep 11 2025 at 17:27):
From what I remember, linters can't use that machinery
Thomas Murrills (Sep 11 2025 at 19:08):
Now that (as of recently) Try This exists as a widget in MessageData, linters can in fact add a clickable suggestion! (But still not the corresponding code action)
Alex Kontorovich (Sep 12 2025 at 14:46):
I'm getting to induction in my Real Analysis Game in a week or two, so would love to know what to tell the students. I guess I can jerry rig my own local version (which would be my preferred: induction n with n hn, which currently requires a prime), but I'd love for it not to be too far from the actual Mathlib usage...? (Not that Mathlib decisions should take my stupid little game into account...)
Eric Wieser (Sep 12 2025 at 17:05):
I don't think we're losing the primed version any time soon, only banning it from mathlib. If we implement Kyle's suggestion, the lesson on translating to mathlib style would teach itself!
Jeremy Tan (Sep 13 2025 at 02:05):
Eric Wieser said:
I don't think we're losing the primed version any time soon, only banning it from mathlib. If we implement Kyle's suggestion, the lesson on translating to mathlib style would teach itself!
Yes, that is my intention. Can you please vote yes in the poll so @Michael Rothgang can maintainer merge?
Patrick Massot (Sep 13 2025 at 09:17):
Thanks, the sentiment of the community is useful information. Note however that this kind of decision is not made by public polls. The maintainers will take it under consideration in internal discussions.
Nailin Guan (Sep 15 2025 at 16:49):
I am a bit unsatisfied with the proccess (not about removing induction', I am nutrual about this), there isn't a suggestion for fixing anywhere, codes just broke and fixing need to read them all over. I noticed this change only until I found this thread, without any prior notification in code or even announce.
Back to the problem itself, how should I trigger the deprecate syntax? Is there an unified way to replace induction' _ with ...... where ...... are about naming the variables?
Kyle Miller (Sep 15 2025 at 17:32):
@Nailin Guan There do not seem to have been any changes to induction' yet, and the change proposed in this thread is to add a deprecation warning, not remove it.
Maybe you're working in a file that doesn't import the tactic? It's in Mathlib.Tactic.Cases.
Ruben Van de Velde (Sep 15 2025 at 17:58):
Yeah, Tactic.Cases used to be pulled in much more widely
Nailin Guan (Sep 16 2025 at 02:26):
Importing this makes things work, thanks.
Aaron Liu (Sep 16 2025 at 02:28):
Well you need to import
Nailin Guan (Sep 16 2025 at 02:36):
Back to my second question, for example what is the ideal way to change induction' z using Polynomial.induction_on' wiith f g hf hg n a into induction ...? I don't think rename_i is good enough?
Antoine Chambert-Loir (Sep 16 2025 at 06:18):
induction z using Polynomial.induction_on' with
| add f g hf hg => sorry
| monomial n a => sorry
Antoine Chambert-Loir (Sep 16 2025 at 06:20):
The names add and monomial come from the definition of docs#Polynomial.induction_on' and, as you can see, the arguments are the same as for the induction' tactic, in the same order, with the advantage (so I feel) that you can switch the add and monomial proofs if you prefer so.
Jeremy Tan (Sep 16 2025 at 08:22):
@Nailin Guan induction' has been banned from mathlib since https://github.com/leanprover-community/mathlib4/commit/5e8936e560f53cd39eb49ed22e93662a0f0a1928
Last updated: Dec 20 2025 at 21:32 UTC