Zulip Chat Archive

Stream: lean4

Topic: matching on inductives with indices


Jovan Gerbscheid (Oct 15 2025 at 12:50):

Is the following code expected to fail?

inductive A : Nat  Type where
| a {n} : A n
| b : A 10

def foo (n : Nat) (x : A n) (y : A 10) : A n :=
  match x with
  | .a => x
  | .b => y

It gives the error

Type mismatch
  x
has type
  A n
but is expected to have type
  A n

Because for some reason the match has introduced another variable n that shadows the previous n, and these ns are not defEq to eachother.

This comes up in the implementation of the ring tactic. A possible workaround is to write

def foo (n : Nat) (x : A n) (y : A 10) : A n :=
  match x with
  | x@(.a) => x
  | .b => y

Floris van Doorn (Oct 15 2025 at 12:59):

This is not unexpected. Since this is an inductive family, you have to always generalize n before doing induction. This also fails:

def bar (n : Nat) (x : A n) (y : A 10) : A n :=
  A.rec (@fun n'  x) y x

There is probably a small trick to get this definition to work...

Floris van Doorn (Oct 15 2025 at 13:02):

Yeah, your workaround is equivalent to

def foo (n : Nat) (x : A n) (y : A 10) : A n :=
  match x with
  | .a => .a
  | .b => y

which of course works.

Floris van Doorn (Oct 15 2025 at 13:07):

I guess match could get a feature that it clears the old x (and n) from the environment, and adds a new x that corresponds to each of the cases. However, I think this is undesirable in other situations (and I'm not sure how this would interact with catch-all patterns and other features of match)

Aaron Liu (Oct 15 2025 at 13:10):

I would expect that x would also be shadowed

Jovan Gerbscheid (Oct 15 2025 at 13:48):

Indeed, looking at the type of the recursor the behaviour makes more sense:

{motive : (a : Nat)  A a  Sort u}
  (a : {n : Nat}  motive n A.a) (b : motive 10 A.b)
  {x : Nat} (t : A x) : motive x t

In my head the recursor looked more like

{motive : (a : Nat)  A a  Sort u} {x : Nat}
  (a : motive x A.a) (b : motive 10 A.b)
  (t : A x) : motive x t

Jovan Gerbscheid (Oct 18 2025 at 06:36):

I have some more unexpected behaviour when matching on inductives with indices. The following throws an error, but if we replace the type A x by A y or A z, it succeeds. In other words, the order of the (x y z : Nat) arguments in the definition ofA makes a difference.

inductive A : Nat  Type where
| a (x y z : Nat) : A x

def foo {n} (a : A n) : A n :=
  match a with
  | .a x y z => .a x y z
/-
Type mismatch
  A.a x y z
has type
  A x
but is expected to have type
  A n
-/

Aaron Liu (Oct 18 2025 at 13:37):

I have also encountered this problem with my types with lots of indices, the solution is to just rope in the indices into the match

inductive A : Nat  Type where
| a (x y z : Nat) : A x

def foo {n} (a : A n) : A n :=
  match n, a with
  | _, .a x y z => .a x y z

Last updated: Dec 20 2025 at 21:32 UTC