Zulip Chat Archive

Stream: new members

Topic: Type unification question


Julia Scheaffer (Sep 01 2025 at 20:59):

I am currently working on a formalizing a stack in Lean, but I am having some trouble convincing Lean that my some of the types are in fact the same. Here are some of the relevant definitions:

/-- A typed heterogeneous stack -/
inductive Stack.{u} : List (Type u) -> Type (u + 1) where
  | nil : Stack []
  | cons {α β}: α -> Stack β -> Stack (α :: β)

infixr:67 "; " => Stack.cons

def Stack.append.{u} {α β : List (Type u)} : Stack α -> Stack β -> Stack (α ++ β)
  | nil, b => b | head; tail, b => head; Stack.append tail b

I would like to try proving that {α : List (Type u)} -> (a : Stack α) -> a.append Stack.nil = a but the compiler complains that Stack (α ++ []) does not match Stack α. Is there a way I can tell lean that these two are the same? (I have proven it's equality) Is the fact that these two types are not judgmentally equal stopping it form working?

Aaron Liu (Sep 01 2025 at 21:02):

I think you should not be trying to prove that a.append Stack.nil = a

Aaron Liu (Sep 01 2025 at 21:03):

also have you seen docs#List.TProd

Julia Scheaffer (Sep 01 2025 at 21:05):

I discovered List.TProd after I wrote this code unfortunately. :sweat_smile:

Julia Scheaffer (Sep 01 2025 at 21:07):

If I were to rewrite my Stack using List.TProd, for the type family α I think I would want to just use id, right?

Aaron Liu (Sep 01 2025 at 21:08):

What I did is I wrote a get function

Aaron Liu said:

import Mathlib

def List.TProd.get {ι : Type u} {α : ι  Type v} {l : List ι}
    (t : l.TProd α) (n : Nat) (i : ι) (hi : i  l[n]?) : α i :=
  match l, n, hi with
  | _ :: _, 0, rfl => t.1
  | _ :: _, n + 1, hi => List.TProd.get t.2 n i hi

and then I proved get_append_of_lt and get_append_of_ge

Julia Scheaffer (Sep 01 2025 at 21:14):

I will try to take that approach instead, thanks. I was hoping to get away with my slightly simpler definition, but TProd will probably end up being better in the long run.

Julia Scheaffer (Sep 02 2025 at 02:49):

Julia Scheaffer said:

I will try to take that approach instead, thanks. I was hoping to get away with my slightly simpler definition, but TProd will probably end up being better in the long run.

I cannot get my code working with List.TProd today. I might try it again another day with some fresh perspective.

Julia Scheaffer (Sep 02 2025 at 02:52):

Is it impossible to convince lean that Stack (α ++ []) and Stack α are compatible types like in my first message? If not I will have to do something else to state these theorems :/

pandaman (Sep 02 2025 at 04:44):

You can lift the pattern to an equality proposition. It's a bit cumbersome, but at least it can avoid dependent pattern match failures.

/-- A typed heterogeneous stack -/
inductive Stack.{u} : List (Type u) -> Type (u + 1) where
  | nil : Stack []
  | cons {α β ts} : α -> Stack β  (ts = α :: β) -> Stack ts

-- infixr:67 "; " => Stack.cons

def Stack.append.{u} {α β : List (Type u)} : Stack α -> Stack β -> Stack (α ++ β)
  | nil, b => b
  | cons a b h, b' => .cons a (append b b') (by simp [h])

pandaman (Sep 02 2025 at 04:49):

Ah sorry, I misunderstood the question. I think we need something like Stack.cast(see #new members > Proofs and casts @ 💬 )

Julia Scheaffer (Sep 02 2025 at 13:01):

pandaman said:

Ah sorry, I misunderstood the question. I think we need something like Stack.cast(see #new members > Proofs and casts @ 💬 )

Thank you for this advice. I will try that out.

Julia Scheaffer (Sep 02 2025 at 17:12):

Thank you for the recommendation @pandaman. I got have some proofs about Stack.append working now!
Also thanks to @Kyle Miller for those Vec exercises, they were a huge help for figuring out how to work with cast.


Last updated: Dec 20 2025 at 21:32 UTC