Zulip Chat Archive
Stream: lean4
Topic: Using rename_i with try
LambdaDuck (Andreas Källberg) (Feb 02 2025 at 00:21):
When I try using try rename_i x
when no inaccessible variables are present, I still get a "too many variable names provided" error despite using try. Is there a workaround?
I'm probably trying to solve the wrong problem though. My actual goal is to get access to all the variables generated from the cases
tactic without having to manually mention each case. Is there a version of the macro that's equivalent to intro h ; cases h ; all_goals revert <all the variables introduced by cases
?
Kyle Miller (Feb 02 2025 at 00:27):
This is a bug in rename_i
. It's merely logging an error, but not aborting execution, so try
doesn't catch it and backtrack. Would you mind reporting it in the Lean 4 github?
Kyle Miller (Feb 02 2025 at 00:28):
For your second question, I suppose this is where a Coq-style ssreflect-style sublanguage could come in handy. In ssreflect, there is a focus on manipulating the target rather than introducing local variables.
If you know what the type is (say it's T
) you could do apply T.recOn
rather than doing intro
first. (Never mind, I thought this would work, but in a test it didn't.)
LambdaDuck (Andreas Källberg) (Feb 02 2025 at 00:43):
I found that using the variable within the try block so that the other tactic can report an error did work, which seems consistent with your description. For example, I could do this to revert all inaccessible variables into arguments for the goal: all_goals repeat rename_i h; revert h
Kyle Miller (Feb 02 2025 at 01:06):
Here's a sketch of a tactic (cases_on
) that does cases
on the first parameter. It doesn't fully implement what cases
does though (like it doesn't pick up on custom eliminators). It's possible to do this by calling out to the cases
tactic, or cases
tactic internals, but I was just experimenting and figured I'd paste it here.
import Lean
open Lean Elab Tactic Meta in
elab "cases_on" : tactic => do
let g0 ← popMainGoal
g0.withContext do
let (x, g) ← g0.intro1
g.withContext do
let dom ← x.getType
matchConstInduct dom.getAppFn
(fun _ => throwError "Expecting type to be an inductive type, not{indentExpr dom}")
(fun ival _ => do
let c ← mkConstWithFreshMVarLevels (mkCasesOnName ival.name)
-- use the g0 context so that `x` doesn't appear in any premises
let (args, _) ← g0.withContext do forallMetaTelescope (← inferType c)
let params := dom.getAppArgs
for i in [0:params.size] do
unless ← isDefEq args[i]! params[i]! do
throwError "(internal error) failed to assign inductive type parameter"
let mut args := args
-- Set major premise (replace the metavariable)
args := args.set! (ival.numParams + 1) (.fvar x)
-- Set remaining arguments as synthetic opaque so they can be tactic goals
let minors := args[ival.numParams + 2 : args.size].toArray.toList.map (·.mvarId!)
for m in minors do
m.setKind .syntheticOpaque
-- Construct recursor application, motive still needs solving-for
let casesOn := mkAppN c args
let gs ← g.apply casesOn
pushGoals gs)
example : (xs : List Nat) → 0 ≤ xs.length := by
cases_on
/-
case nil
⊢ 0 ≤ [].length
case cons
⊢ ∀ (head : Nat) (tail : List Nat), 0 ≤ (head :: tail).length
-/
Last updated: May 02 2025 at 03:31 UTC