Zulip Chat Archive

Stream: metaprogramming / tactics

Topic: naming metavariables after the fact


Scott Morrison (May 12 2022 at 01:19):

Sometimes it is convenient (or good pedagogy) to "leave a metavariable for later" in a proof.

However when we do this in Lean 3 this leaves ?m_i names in the proof state, which are highly confusing to people who haven't thought about metavariables, and unpleasant to read for anyone.

Is there a good way to give names to metavariables after the fact? Here's an example of what I would like:

example : Σ {α : Type},   α :=
begin
  fsplit,
  /- The goals are:
  ```
  ⊢ Type

  ⊢ ℕ → ?m_1
  ```

  I would like them to be:
  ```
  ⊢ Type

  α : Type := ?m_1
  ⊢ ℕ → α
  ```
  -/
  exact , exact id,
end

Lean 4 has a nice mechanism for naming metavariables at the time they are created (i.e. using in place of _ in a refine statement), but I'm interested in Lean 3 solutions for now.

One solution is to replace the fsplit above with

  let α := _,
  refine α, _⟩,

and this gives me the desired goals.

However I am specifically interested in solutions that work after the fact. I'll post below a more involved example where the let α := _ trick doesn't work, as well.

Johan Commelin (May 12 2022 at 05:31):

I'd be interested in that more involved example!

Scott Morrison (May 12 2022 at 07:27):

Sorry, paused on the more involved example to ask my parallel question about to_expr. Essentially it's implicit there: when you use refine, you can't generate typeclass failures as new goals, while fsplit can. Thus the let trick, which requires refine, will fail if some of the other underscores are typeclasses depending on the named metavariable.

Johan Commelin (May 12 2022 at 07:29):

True. Note that refine @foobar.mk α (id _) (id _) (id _) quux xyzzy would work. But it is of course very ugly.

Johan Commelin (May 12 2022 at 07:30):

The main point being that (id _) will turn a typeclass argument into a new goal.

Scott Morrison (May 12 2022 at 08:46):

So is this some difference between elaborating with an expected type vs without? That when elaborating with an expected type, failed typeclasses searches are just failure. But if we insert (id _) the expect type can't propagate down that far, so the elaboration mode switches, and the typeclass searches instead result in new goals...

Scott Morrison (May 12 2022 at 08:47):

This makes me uncertain whether I should be thinking up some hacky refine' that inserts id in places, or hoping that it is possible or reasonable to change the behaviour of elaboration-with-expected-type so we still get the failed typeclass searches as goals.

Johan Commelin (May 12 2022 at 08:50):

I've never looked under the hood of tactic#apply_with but you can pass it a config option {instances := ff} that turns all typeclass arguments into new goals.

Scott Morrison (May 12 2022 at 10:51):

I don't think that argument for apply is relevant. It's the all in the difference between typeclass failures causing failure in to_expr with an expected type, vs causing new goals in to_expr without an expected type.

Scott Morrison (May 12 2022 at 10:51):

I don't understand why there would be that difference in behaviour.

Scott Morrison (May 12 2022 at 10:51):

And my limited attempts to find it in the C++ have not been very successful. :-)


Last updated: Dec 20 2023 at 11:08 UTC