Zulip Chat Archive

Stream: lean4

Topic: Alternate constructor code action


Oliver Nash (Feb 02 2024 at 11:09):

Kevin highlighted this very nice PR https://github.com/leanprover/std4/pull/577 to me earlier this morning. It makes me wonder if we could ask for even more!

There are various places in Mathlib where we have multiple constructors available for a given structure and it would be lovely if the "generate skeleton" code action could offer the user a choice in such cases.

Oliver Nash (Feb 02 2024 at 11:13):

So for example in this situation:

import Mathlib

variable {G : Type*} [Group G]

example (H : Subgroup G) : Group H := _

Oliver Nash (Feb 02 2024 at 11:14):

The code action would provide a little menu allowing me to choose to use docs#Group.ofLeftAxioms and leaving me in the new state:

import Mathlib

variable {G : Type*} [Group G]

example (H : Subgroup G) : Group H :=
  Group.ofLeftAxioms _ _ _

Oliver Nash (Feb 02 2024 at 11:14):

Any thoughts @Mario Carneiro ?

Mario Carneiro (Feb 02 2024 at 11:19):

PSA: don't be afraid to ask for features in this regard! The behavior Kevin highlighted is easily solved, the main question is determining what users want in the first place

Mario Carneiro (Feb 02 2024 at 11:21):

To implement this, we would need some tagging system for "smart constructors"

Oliver Nash (Feb 02 2024 at 11:21):

@[constructor]?

Mario Carneiro (Feb 02 2024 at 11:22):

would it work on non-structures?

Mario Carneiro (Feb 02 2024 at 11:23):

another observation is that we might want to phase out smart constructors in favor of something more like haskell's minimal sets in the future, in which case you wouldn't even need to mention ofLeftAxioms by name

Oliver Nash (Feb 02 2024 at 11:24):

Mario Carneiro said:

would it work on non-structures?

I don't think I get this point: to me Lean has only three things, def, structure, theorem.

Mario Carneiro (Feb 02 2024 at 11:24):

right, so would it work on defs

Mario Carneiro (Feb 02 2024 at 11:25):

I think it would be better (performance-wise) if the answer was 'no'

Oliver Nash (Feb 02 2024 at 11:25):

I say no, but I might change my mind if someone comes up with an example where this would be desirable.

Eric Rodriguez (Feb 02 2024 at 11:27):

Mario Carneiro said:

another observation is that we might want to phase out smart constructors in favor of something more like haskell's minimal sets in the future, in which case you wouldn't even need to mention ofLeftAxioms by name

what would this do?

Mario Carneiro (Feb 02 2024 at 11:27):

I think we might want to have a more extensible notion of what a 'structure' is in the future, such that structure instances and the like work even though they aren't literally inductive types implemented by the structure command

Mario Carneiro (Feb 02 2024 at 11:27):

for example, coinductive types really need this to be usable

Eric Rodriguez (Feb 02 2024 at 11:27):

I'm also confused why using lemmas tagged as @[constructor] for non-structures would be slow

Mario Carneiro (Feb 02 2024 at 11:28):

because it's no good defining a thing which is isomorphic to the coinductive type you want but then tactics like cases and induction totally ignore the inductive-like view and just complain that it has some other implementation detail definition

Oliver Nash (Feb 02 2024 at 11:29):

Unfortunately I have a call now so I must disappear but I'm already very grateful that this idea is being considered.

Mario Carneiro (Feb 02 2024 at 11:29):

Eric Rodriguez said:

I'm also confused why using lemmas tagged as @[constructor] for non-structures would be slow

Code actions are performance-sensitive, it's the difference between running this code on every _ and on ones that have structure type

Eric Rodriguez (Feb 02 2024 at 11:31):

oh, I see, because you need to identify that _ is actually wanting to trigger a code action. Maybe it should have a different syntax? or is it desired that, e.g., refine ?_ ?_ ?_ _ _ would let you run code actions on the end two _s?

Mario Carneiro (Feb 02 2024 at 11:31):

hole code actions run on any _ or ?_

Eric Rodriguez (Feb 02 2024 at 11:32):

I think it'd be nice to have @[constructor] on anything, likely with a different signifier for code actions, but I think that's probably way beyond what this feature needs; I think it'd be fine to limit it to structures as-is

Mario Carneiro (Feb 02 2024 at 11:32):

what else would you use @[constructor] for?

Eric Rodriguez (Feb 02 2024 at 11:34):

type synonyms are the only things that come to mind quickly, hmm

Mario Carneiro (Feb 02 2024 at 11:35):

no, I mean what other purpose would you put them to, besides the code action

Johan Commelin (Feb 02 2024 at 11:35):

@Mario Carneiro Could the code action just be "Fill in a skeleton for _", and only when the user selects it, the code action starts looking up available @[constructor]s?

Johan Commelin (Feb 02 2024 at 11:35):

That would mean that it could even be an expensive action, because it almost never runs. Only when the user intends it to.

Mario Carneiro (Feb 02 2024 at 11:35):

no, because code actions don't have staged evaluation

Mario Carneiro (Feb 02 2024 at 11:36):

you present options, the user selects one, the text is edited

Johan Commelin (Feb 02 2024 at 11:36):

And we can't hack them to do that?

Mario Carneiro (Feb 02 2024 at 11:36):

not that I know of

Johan Commelin (Feb 02 2024 at 11:36):

The text is edited to become (by choose_skeleton). And choose_skeleton is a tactic that displays options in a widget view.

Eric Rodriguez (Feb 02 2024 at 11:36):

Mario Carneiro said:

no, I mean what other purpose would you put them to, besides the code action

oh I meant some other _-like thing, so as to not slow down normal code actions. Maybe something used more rarely within normal Lean code

Mario Carneiro (Feb 02 2024 at 11:36):

lol

Mario Carneiro (Feb 02 2024 at 11:37):

It's not as bad as that @Eric Rodriguez , it only runs on the _ where the cursor is

Mario Carneiro (Feb 02 2024 at 11:38):

the main performance issue is that it runs on every cursor motion

Mario Carneiro (Feb 02 2024 at 11:38):

but if you don't put the cursor over a _ then the framework never calls the hole code action

Oliver Nash (Feb 02 2024 at 12:10):

I say we just declare that this is a structure-only feature then.

Kevin Buzzard (Feb 02 2024 at 12:16):

As I've said in the other thread, the place where this would be great for me is when undergraduates are making an type with two terms and then attempting to put a group structure on it without being totally bamboozled by (a) DivInvMonoids (which is what happens if you read the source code) or (b) nsmul (which is what happens if you use the code action).

Kevin Buzzard (Feb 02 2024 at 12:21):

But Chris Hughes wrote some really nice (minimal) constructors for Groupand if we can use those then even better!

Eric Wieser (Feb 03 2024 at 11:10):

A related feature, when building instances, would be to not generate fields that can be found by inferInstance

Eric Wieser (Feb 03 2024 at 11:10):

If I've already shown AddCommGroup X I don't want to generate a skeleton with all the fields again when proving NormedGroup X

Mario Carneiro (Feb 03 2024 at 11:12):

I think the "minimal structure" PR will do that automatically, let me double check

Mario Carneiro (Feb 03 2024 at 11:12):

it's supposed to yield the same list of fields that you would get in the error message if you omitted everything

Kevin Buzzard (Feb 03 2024 at 11:21):

Yeah -- I'm pretty sure that's a good strat because it's the one I use in practice when I can't be bothered to delete all the nsmul's

Eric Wieser (Feb 03 2024 at 16:25):

I think I'm requesting a variant that fills in all the fields that inferInstance implies, but not the ones with default values

Eric Wieser (Feb 03 2024 at 16:26):

Though maybe that would be better handled by my previous suggestion to replace default values with nsmul := by default or something explicit in the source code that makes it clear that a default is being used behind the scenes

Matthew Ballard (Feb 03 2024 at 16:49):

It shouldn’t be terrible to log a more informative error during elaboration of the default values. Even with that, there is value in wrapping default values in a tactic


Last updated: May 02 2025 at 03:31 UTC