l3lab/ntp-mathlib huggingface dataset:
/-- Given two `BlankRel` lists, there exists (constructively) a common join. -/
def BlankRel.above {Γ} [Inhabited Γ] {l₁ l₂ : List Γ} (h : BlankRel l₁ l₂) :
    { l // BlankExtends l₁ l ∧ BlankExtends l₂ l } := by
  refine'
    if hl : l₁.length ≤ l₂.length then ⟨l₂, Or.elim h id fun h' ↦ _, BlankExtends.refl _⟩
    else ⟨l₁, BlankExtends.refl _, Or.elim h (fun h' ↦ _) id⟩
  exact (BlankExtends.refl _).above_of_le h' hl
  

Proof state:
case refine'_2
Γ : Type ?u.9819
inst✝ : Inhabited Γ
l₁ l₂ : List Γ
h : BlankRel l₁ l₂
hl : ¬List.length l₁ ≤ List.length l₂
h' : BlankExtends l₁ l₂
⊢ BlankExtends l₂ l₁

Next tactic:
exact (BlankExtends.refl _).above_of_le h' (le_of_not_ge hl)
/-- Given two `BlankRel` lists, there exists (constructively) a common meet. -/
def BlankRel.below {Γ} [Inhabited Γ] {l₁ l₂ : List Γ} (h : BlankRel l₁ l₂) :
    { l // BlankExtends l l₁ ∧ BlankExtends l l₂ } := by
  

Proof state:
Γ : Type ?u.11402
inst✝ : Inhabited Γ
l₁ l₂ : List Γ
h : BlankRel l₁ l₂
⊢ { l // BlankExtends l l₁ ∧ BlankExtends l l₂ }

Next tactic:
refine'
    if hl : l₁.length ≤ l₂.length then ⟨l₁, BlankExtends.refl _, Or.elim h id fun h' ↦ _⟩
    else ⟨l₂, Or.elim h (fun h' ↦ _) id, BlankExtends.refl _⟩
/-- Given two `BlankRel` lists, there exists (constructively) a common meet. -/
def BlankRel.below {Γ} [Inhabited Γ] {l₁ l₂ : List Γ} (h : BlankRel l₁ l₂) :
    { l // BlankExtends l l₁ ∧ BlankExtends l l₂ } := by
  refine'
    if hl : l₁.length ≤ l₂.length then ⟨l₁, BlankExtends.refl _, Or.elim h id fun h' ↦ _⟩
    else ⟨l₂, Or.elim h (fun h' ↦ _) id, BlankExtends.refl _⟩
  

Proof state:
case refine'_1
Γ : Type ?u.11402
inst✝ : Inhabited Γ
l₁ l₂ : List Γ
h : BlankRel l₁ l₂
hl : List.length l₁ ≤ List.length l₂
h' : BlankExtends l₂ l₁
⊢ BlankExtends l₁ l₂
case refine'_2
Γ : Type ?u.11402
inst✝ : Inhabited Γ
l₁ l₂ : List Γ
h : BlankRel l₁ l₂
hl : ¬List.length l₁ ≤ List.length l₂
h' : BlankExtends l₁ l₂
⊢ BlankExtends l₂ l₁

Next tactic:
exact (BlankExtends.refl _).above_of_le h' hl
/-- Given two `BlankRel` lists, there exists (constructively) a common meet. -/
def BlankRel.below {Γ} [Inhabited Γ] {l₁ l₂ : List Γ} (h : BlankRel l₁ l₂) :
    { l // BlankExtends l l₁ ∧ BlankExtends l l₂ } := by
  refine'
    if hl : l₁.length ≤ l₂.length then ⟨l₁, BlankExtends.refl _, Or.elim h id fun h' ↦ _⟩
    else ⟨l₂, Or.elim h (fun h' ↦ _) id, BlankExtends.refl _⟩
  exact (BlankExtends.refl _).above_of_le h' hl
  

Proof state:
case refine'_2
Γ : Type ?u.11402
inst✝ : Inhabited Γ
l₁ l₂ : List Γ
h : BlankRel l₁ l₂
hl : ¬List.length l₁ ≤ List.length l₂
h' : BlankExtends l₁ l₂
⊢ BlankExtends l₂ l₁

Next tactic:
exact (BlankExtends.refl _).above_of_le h' (le_of_not_ge hl)
/-- A modified version of `Quotient.liftOn'` specialized for `ListBlank`, with the stronger
precondition `BlankExtends` instead of `BlankRel`. -/
@[reducible]  -- Porting note: Removed `@[elab_as_elim]`
protected def ListBlank.liftOn {Γ} [Inhabited Γ] {α} (l : ListBlank Γ) (f : List Γ → α)
    (H : ∀ a b, BlankExtends a b → f a = f b) : α :=
  l.liftOn' f <| by 

Proof state:
Γ : Type ?u.13994
inst✝ : Inhabited Γ
α : Sort ?u.14006
l : ListBlank Γ
f : List Γ → α
H : ∀ (a b : List Γ), BlankExtends a b → f a = f b
⊢ ∀ (a b : List Γ), Setoid.r a b → f a = f b

Next tactic:
rintro a b (h | h) <;> [exact H _ _ h; exact (H _ _ h).symm]
/-- A modified version of `Quotient.liftOn'` specialized for `ListBlank`, with the stronger
precondition `BlankExtends` instead of `BlankRel`. -/
@[reducible]  -- Porting note: Removed `@[elab_as_elim]`
protected def ListBlank.liftOn {Γ} [Inhabited Γ] {α} (l : ListBlank Γ) (f : List Γ → α)
    (H : ∀ a b, BlankExtends a b → f a = f b) : α :=
  l.liftOn' f <| by 

Proof state:
Γ : Type ?u.13994
inst✝ : Inhabited Γ
α : Sort ?u.14006
l : ListBlank Γ
f : List Γ → α
H : ∀ (a b : List Γ), BlankExtends a b → f a = f b
⊢ ∀ (a b : List Γ), Setoid.r a b → f a = f b

Next tactic:
rintro a b (h | h)
/-- A modified version of `Quotient.liftOn'` specialized for `ListBlank`, with the stronger
precondition `BlankExtends` instead of `BlankRel`. -/
@[reducible]  -- Porting note: Removed `@[elab_as_elim]`
protected def ListBlank.liftOn {Γ} [Inhabited Γ] {α} (l : ListBlank Γ) (f : List Γ → α)
    (H : ∀ a b, BlankExtends a b → f a = f b) : α :=
  l.liftOn' f <| by rintro a b (h | h) <;> [

Proof state:
case inl
Γ : Type ?u.13994
inst✝ : Inhabited Γ
α : Sort ?u.14006
l : ListBlank Γ
f : List Γ → α
H : ∀ (a b : List Γ), BlankExtends a b → f a = f b
a b : List Γ
h : BlankExtends a b
⊢ f a = f b

Next tactic:
exact H _ _ h
/-- A modified version of `Quotient.liftOn'` specialized for `ListBlank`, with the stronger
precondition `BlankExtends` instead of `BlankRel`. -/
@[reducible]  -- Porting note: Removed `@[elab_as_elim]`
protected def ListBlank.liftOn {Γ} [Inhabited Γ] {α} (l : ListBlank Γ) (f : List Γ → α)
    (H : ∀ a b, BlankExtends a b → f a = f b) : α :=
  l.liftOn' f <| by rintro a b (h | h) <;> [exact H _ _ h; 

Proof state:
case inr
Γ : Type ?u.13994
inst✝ : Inhabited Γ
α : Sort ?u.14006
l : ListBlank Γ
f : List Γ → α
H : ∀ (a b : List Γ), BlankExtends a b → f a = f b
a b : List Γ
h : BlankExtends b a
⊢ f a = f b

Next tactic:
exact (H _ _ h).symm
/-- The head of a `ListBlank` is well defined. -/
def ListBlank.head {Γ} [Inhabited Γ] (l : ListBlank Γ) : Γ := by
  

Proof state:
Γ : Type ?u.15100
inst✝ : Inhabited Γ
l : ListBlank Γ
⊢ Γ

Next tactic:
apply l.liftOn List.headI
/-- The head of a `ListBlank` is well defined. -/
def ListBlank.head {Γ} [Inhabited Γ] (l : ListBlank Γ) : Γ := by
  apply l.liftOn List.headI
  

Proof state:
Γ : Type ?u.15100
inst✝ : Inhabited Γ
l : ListBlank Γ
⊢ ∀ (a b : List Γ), BlankExtends a b → List.headI a = List.headI b

Next tactic:
rintro a _ ⟨i, rfl⟩
/-- The head of a `ListBlank` is well defined. -/
def ListBlank.head {Γ} [Inhabited Γ] (l : ListBlank Γ) : Γ := by
  apply l.liftOn List.headI
  rintro a _ ⟨i, rfl⟩
  

Proof state:
case intro
Γ : Type ?u.15100
inst✝ : Inhabited Γ
l : ListBlank Γ
a : List Γ
i : ℕ
⊢ List.headI a = List.headI (a ++ List.replicate i default)

Next tactic:
cases a
/-- The head of a `ListBlank` is well defined. -/
def ListBlank.head {Γ} [Inhabited Γ] (l : ListBlank Γ) : Γ := by
  apply l.liftOn List.headI
  rintro a _ ⟨i, rfl⟩
  cases a
  · 

Proof state:
case intro.nil
Γ : Type ?u.15100
inst✝ : Inhabited Γ
l : ListBlank Γ
i : ℕ
⊢ List.headI [] = List.headI ([] ++ List.replicate i default)

Next tactic:
cases i
/-- The head of a `ListBlank` is well defined. -/
def ListBlank.head {Γ} [Inhabited Γ] (l : ListBlank Γ) : Γ := by
  apply l.liftOn List.headI
  rintro a _ ⟨i, rfl⟩
  cases a
  · cases i <;> 

Proof state:
case intro.nil.zero
Γ : Type ?u.15100
inst✝ : Inhabited Γ
l : ListBlank Γ
⊢ List.headI [] = List.headI ([] ++ List.replicate Nat.zero default)

Next tactic:
rfl
/-- The head of a `ListBlank` is well defined. -/
def ListBlank.head {Γ} [Inhabited Γ] (l : ListBlank Γ) : Γ := by
  apply l.liftOn List.headI
  rintro a _ ⟨i, rfl⟩
  cases a
  · cases i <;> 

Proof state:
case intro.nil.succ
Γ : Type ?u.15100
inst✝ : Inhabited Γ
l : ListBlank Γ
n✝ : ℕ
⊢ List.headI [] = List.headI ([] ++ List.replicate (Nat.succ n✝) default)

Next tactic:
rfl
/-- The head of a `ListBlank` is well defined. -/
def ListBlank.head {Γ} [Inhabited Γ] (l : ListBlank Γ) : Γ := by
  apply l.liftOn List.headI
  rintro a _ ⟨i, rfl⟩
  cases a
  · cases i <;> rfl
  

Proof state:
case intro.cons
Γ : Type ?u.15100
inst✝ : Inhabited Γ
l : ListBlank Γ
i : ℕ
head✝ : Γ
tail✝ : List Γ
⊢ List.headI (head✝ :: tail✝) = List.headI (head✝ :: tail✝ ++ List.replicate i default)

Next tactic:
rfl
/-- The tail of a `ListBlank` is well defined (up to the tail of blanks). -/
def ListBlank.tail {Γ} [Inhabited Γ] (l : ListBlank Γ) : ListBlank Γ := by
  

Proof state:
Γ : Type ?u.15920
inst✝ : Inhabited Γ
l : ListBlank Γ
⊢ ListBlank Γ

Next tactic:
apply l.liftOn (fun l ↦ ListBlank.mk l.tail)
/-- The tail of a `ListBlank` is well defined (up to the tail of blanks). -/
def ListBlank.tail {Γ} [Inhabited Γ] (l : ListBlank Γ) : ListBlank Γ := by
  apply l.liftOn (fun l ↦ ListBlank.mk l.tail)
  

Proof state:
Γ : Type ?u.15920
inst✝ : Inhabited Γ
l : ListBlank Γ
⊢ ∀ (a b : List Γ), BlankExtends a b → mk (List.tail a) = mk (List.tail b)

Next tactic:
rintro a _ ⟨i, rfl⟩
/-- The tail of a `ListBlank` is well defined (up to the tail of blanks). -/
def ListBlank.tail {Γ} [Inhabited Γ] (l : ListBlank Γ) : ListBlank Γ := by
  apply l.liftOn (fun l ↦ ListBlank.mk l.tail)
  rintro a _ ⟨i, rfl⟩
  

Proof state:
case intro
Γ : Type ?u.15920
inst✝ : Inhabited Γ
l : ListBlank Γ
a : List Γ
i : ℕ
⊢ mk (List.tail a) = mk (List.tail (a ++ List.replicate i default))

Next tactic:
refine' Quotient.sound' (Or.inl _)
/-- The tail of a `ListBlank` is well defined (up to the tail of blanks). -/
def ListBlank.tail {Γ} [Inhabited Γ] (l : ListBlank Γ) : ListBlank Γ := by
  apply l.liftOn (fun l ↦ ListBlank.mk l.tail)
  rintro a _ ⟨i, rfl⟩
  refine' Quotient.sound' (Or.inl _)
  

Proof state:
case intro
Γ : Type ?u.15920
inst✝ : Inhabited Γ
l : ListBlank Γ
a : List Γ
i : ℕ
⊢ BlankExtends (List.tail a) (List.tail (a ++ List.replicate i default))

Next tactic:
cases a
/-- The tail of a `ListBlank` is well defined (up to the tail of blanks). -/
def ListBlank.tail {Γ} [Inhabited Γ] (l : ListBlank Γ) : ListBlank Γ := by
  apply l.liftOn (fun l ↦ ListBlank.mk l.tail)
  rintro a _ ⟨i, rfl⟩
  refine' Quotient.sound' (Or.inl _)
  cases a
  · 

Proof state:
case intro.nil
Γ : Type ?u.15920
inst✝ : Inhabited Γ
l : ListBlank Γ
i : ℕ
⊢ BlankExtends (List.tail []) (List.tail ([] ++ List.replicate i default))

Next tactic:
cases' i with i <;> [exact ⟨0, rfl⟩; exact ⟨i, rfl⟩]
/-- The tail of a `ListBlank` is well defined (up to the tail of blanks). -/
def ListBlank.tail {Γ} [Inhabited Γ] (l : ListBlank Γ) : ListBlank Γ := by
  apply l.liftOn (fun l ↦ ListBlank.mk l.tail)
  rintro a _ ⟨i, rfl⟩
  refine' Quotient.sound' (Or.inl _)
  cases a
  · 

Proof state:
case intro.nil
Γ : Type ?u.15920
inst✝ : Inhabited Γ
l : ListBlank Γ
i : ℕ
⊢ BlankExtends (List.tail []) (List.tail ([] ++ List.replicate i default))

Next tactic:
cases' i with i
/-- The tail of a `ListBlank` is well defined (up to the tail of blanks). -/
def ListBlank.tail {Γ} [Inhabited Γ] (l : ListBlank Γ) : ListBlank Γ := by
  apply l.liftOn (fun l ↦ ListBlank.mk l.tail)
  rintro a _ ⟨i, rfl⟩
  refine' Quotient.sound' (Or.inl _)
  cases a
  · cases' i with i <;> [

Proof state:
case intro.nil.zero
Γ : Type ?u.15920
inst✝ : Inhabited Γ
l : ListBlank Γ
⊢ BlankExtends (List.tail []) (List.tail ([] ++ List.replicate Nat.zero default))

Next tactic:
exact ⟨0, rfl⟩
/-- The tail of a `ListBlank` is well defined (up to the tail of blanks). -/
def ListBlank.tail {Γ} [Inhabited Γ] (l : ListBlank Γ) : ListBlank Γ := by
  apply l.liftOn (fun l ↦ ListBlank.mk l.tail)
  rintro a _ ⟨i, rfl⟩
  refine' Quotient.sound' (Or.inl _)
  cases a
  · cases' i with i <;> [exact ⟨0, rfl⟩; 

Proof state:
case intro.nil.succ
Γ : Type ?u.15920
inst✝ : Inhabited Γ
l : ListBlank Γ
i : ℕ
⊢ BlankExtends (List.tail []) (List.tail ([] ++ List.replicate (Nat.succ i) default))

Next tactic:
exact ⟨i, rfl⟩
/-- The tail of a `ListBlank` is well defined (up to the tail of blanks). -/
def ListBlank.tail {Γ} [Inhabited Γ] (l : ListBlank Γ) : ListBlank Γ := by
  apply l.liftOn (fun l ↦ ListBlank.mk l.tail)
  rintro a _ ⟨i, rfl⟩
  refine' Quotient.sound' (Or.inl _)
  cases a
  · cases' i with i <;> [exact ⟨0, rfl⟩; exact ⟨i, rfl⟩]
  

Proof state:
case intro.cons
Γ : Type ?u.15920
inst✝ : Inhabited Γ
l : ListBlank Γ
i : ℕ
head✝ : Γ
tail✝ : List Γ
⊢ BlankExtends (List.tail (head✝ :: tail✝)) (List.tail (head✝ :: tail✝ ++ List.replicate i default))

Next tactic:
exact ⟨i, rfl⟩
/-- We can cons an element onto a `ListBlank`. -/
def ListBlank.cons {Γ} [Inhabited Γ] (a : Γ) (l : ListBlank Γ) : ListBlank Γ := by
  

Proof state:
Γ : Type ?u.16961
inst✝ : Inhabited Γ
a : Γ
l : ListBlank Γ
⊢ ListBlank Γ

Next tactic:
apply l.liftOn (fun l ↦ ListBlank.mk (List.cons a l))
/-- We can cons an element onto a `ListBlank`. -/
def ListBlank.cons {Γ} [Inhabited Γ] (a : Γ) (l : ListBlank Γ) : ListBlank Γ := by
  apply l.liftOn (fun l ↦ ListBlank.mk (List.cons a l))
  

Proof state:
Γ : Type ?u.16961
inst✝ : Inhabited Γ
a : Γ
l : ListBlank Γ
⊢ ∀ (a_1 b : List Γ), BlankExtends a_1 b → mk (a :: a_1) = mk (a :: b)

Next tactic:
rintro _ _ ⟨i, rfl⟩
/-- We can cons an element onto a `ListBlank`. -/
def ListBlank.cons {Γ} [Inhabited Γ] (a : Γ) (l : ListBlank Γ) : ListBlank Γ := by
  apply l.liftOn (fun l ↦ ListBlank.mk (List.cons a l))
  rintro _ _ ⟨i, rfl⟩
  

Proof state:
case intro
Γ : Type ?u.16961
inst✝ : Inhabited Γ
a : Γ
l : ListBlank Γ
a✝ : List Γ
i : ℕ
⊢ mk (a :: a✝) = mk (a :: (a✝ ++ List.replicate i default))

Next tactic:
exact Quotient.sound' (Or.inl ⟨i, rfl⟩)
/-- The `cons` and `head`/`tail` functions are mutually inverse, unlike in the case of `List` where
this only holds for nonempty lists. -/
@[simp]
theorem ListBlank.cons_head_tail {Γ} [Inhabited Γ] : ∀ l : ListBlank Γ, l.tail.cons l.head = l := by
  

Proof state:
Γ : Type u_1
inst✝ : Inhabited Γ
⊢ ∀ (l : ListBlank Γ), cons (head l) (tail l) = l

Next tactic:
apply Quotient.ind'
/-- The `cons` and `head`/`tail` functions are mutually inverse, unlike in the case of `List` where
this only holds for nonempty lists. -/
@[simp]
theorem ListBlank.cons_head_tail {Γ} [Inhabited Γ] : ∀ l : ListBlank Γ, l.tail.cons l.head = l := by
  apply Quotient.ind'
  

Proof state:
case h
Γ : Type u_1
inst✝ : Inhabited Γ
⊢ ∀ (a : List Γ), cons (head (Quotient.mk'' a)) (tail (Quotient.mk'' a)) = Quotient.mk'' a

Next tactic:
refine' fun l ↦ Quotient.sound' (Or.inr _)
/-- The `cons` and `head`/`tail` functions are mutually inverse, unlike in the case of `List` where
this only holds for nonempty lists. -/
@[simp]
theorem ListBlank.cons_head_tail {Γ} [Inhabited Γ] : ∀ l : ListBlank Γ, l.tail.cons l.head = l := by
  apply Quotient.ind'
  refine' fun l ↦ Quotient.sound' (Or.inr _)
  

Proof state:
case h
Γ : Type u_1
inst✝ : Inhabited Γ
l : List Γ
⊢ BlankExtends l (head (Quotient.mk'' l) :: List.tail l)

Next tactic:
cases l
/-- The `cons` and `head`/`tail` functions are mutually inverse, unlike in the case of `List` where
this only holds for nonempty lists. -/
@[simp]
theorem ListBlank.cons_head_tail {Γ} [Inhabited Γ] : ∀ l : ListBlank Γ, l.tail.cons l.head = l := by
  apply Quotient.ind'
  refine' fun l ↦ Quotient.sound' (Or.inr _)
  cases l
  · 

Proof state:
case h.nil
Γ : Type u_1
inst✝ : Inhabited Γ
⊢ BlankExtends [] (head (Quotient.mk'' []) :: List.tail [])

Next tactic:
exact ⟨1, rfl⟩
/-- The `cons` and `head`/`tail` functions are mutually inverse, unlike in the case of `List` where
this only holds for nonempty lists. -/
@[simp]
theorem ListBlank.cons_head_tail {Γ} [Inhabited Γ] : ∀ l : ListBlank Γ, l.tail.cons l.head = l := by
  apply Quotient.ind'
  refine' fun l ↦ Quotient.sound' (Or.inr _)
  cases l
  · exact ⟨1, rfl⟩
  · 

Proof state:
case h.cons
Γ : Type u_1
inst✝ : Inhabited Γ
head✝ : Γ
tail✝ : List Γ
⊢ BlankExtends (head✝ :: tail✝) (head (Quotient.mk'' (head✝ :: tail✝)) :: List.tail (head✝ :: tail✝))

Next tactic:
rfl
/-- The n-th element of a `ListBlank` is well defined for all `n : ℕ`, unlike in a `List`. -/
def ListBlank.nth {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) : Γ := by
  

Proof state:
Γ : Type ?u.18768
inst✝ : Inhabited Γ
l : ListBlank Γ
n : ℕ
⊢ Γ

Next tactic:
apply l.liftOn (fun l ↦ List.getI l n)
/-- The n-th element of a `ListBlank` is well defined for all `n : ℕ`, unlike in a `List`. -/
def ListBlank.nth {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) : Γ := by
  apply l.liftOn (fun l ↦ List.getI l n)
  

Proof state:
Γ : Type ?u.18768
inst✝ : Inhabited Γ
l : ListBlank Γ
n : ℕ
⊢ ∀ (a b : List Γ), BlankExtends a b → List.getI a n = List.getI b n

Next tactic:
rintro l _ ⟨i, rfl⟩
/-- The n-th element of a `ListBlank` is well defined for all `n : ℕ`, unlike in a `List`. -/
def ListBlank.nth {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) : Γ := by
  apply l.liftOn (fun l ↦ List.getI l n)
  rintro l _ ⟨i, rfl⟩
  

Proof state:
case intro
Γ : Type ?u.18768
inst✝ : Inhabited Γ
l✝ : ListBlank Γ
n : ℕ
l : List Γ
i : ℕ
⊢ List.getI l n = List.getI (l ++ List.replicate i default) n

Next tactic:
cases' lt_or_le n _ with h h
/-- The n-th element of a `ListBlank` is well defined for all `n : ℕ`, unlike in a `List`. -/
def ListBlank.nth {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) : Γ := by
  apply l.liftOn (fun l ↦ List.getI l n)
  rintro l _ ⟨i, rfl⟩
  cases' lt_or_le n _ with h h
  · 

Proof state:
case intro.inl
Γ : Type ?u.18768
inst✝ : Inhabited Γ
l✝ : ListBlank Γ
n : ℕ
l : List Γ
i : ℕ
h : n < ?m.19049
⊢ List.getI l n = List.getI (l ++ List.replicate i default) n

Next tactic:
rw [List.getI_append _ _ _ h]
/-- The n-th element of a `ListBlank` is well defined for all `n : ℕ`, unlike in a `List`. -/
def ListBlank.nth {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) : Γ := by
  apply l.liftOn (fun l ↦ List.getI l n)
  rintro l _ ⟨i, rfl⟩
  cases' lt_or_le n _ with h h
  · rw [List.getI_append _ _ _ h]
  

Proof state:
case intro.inr
Γ : Type ?u.18768
inst✝ : Inhabited Γ
l✝ : ListBlank Γ
n : ℕ
l : List Γ
i : ℕ
h : List.length l ≤ n
⊢ List.getI l n = List.getI (l ++ List.replicate i default) n

Next tactic:
rw [List.getI_eq_default _ h]
/-- The n-th element of a `ListBlank` is well defined for all `n : ℕ`, unlike in a `List`. -/
def ListBlank.nth {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) : Γ := by
  apply l.liftOn (fun l ↦ List.getI l n)
  rintro l _ ⟨i, rfl⟩
  cases' lt_or_le n _ with h h
  · rw [List.getI_append _ _ _ h]
  rw [List.getI_eq_default _ h]
  

Proof state:
case intro.inr
Γ : Type ?u.18768
inst✝ : Inhabited Γ
l✝ : ListBlank Γ
n : ℕ
l : List Γ
i : ℕ
h : List.length l ≤ n
⊢ default = List.getI (l ++ List.replicate i default) n

Next tactic:
rcases le_or_lt _ n with h₂ | h₂
/-- The n-th element of a `ListBlank` is well defined for all `n : ℕ`, unlike in a `List`. -/
def ListBlank.nth {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) : Γ := by
  apply l.liftOn (fun l ↦ List.getI l n)
  rintro l _ ⟨i, rfl⟩
  cases' lt_or_le n _ with h h
  · rw [List.getI_append _ _ _ h]
  rw [List.getI_eq_default _ h]
  rcases le_or_lt _ n with h₂ | h₂
  · 

Proof state:
case intro.inr.inl
Γ : Type ?u.18768
inst✝ : Inhabited Γ
l✝ : ListBlank Γ
n : ℕ
l : List Γ
i : ℕ
h : List.length l ≤ n
h₂ : ?m.19546 ≤ n
⊢ default = List.getI (l ++ List.replicate i default) n

Next tactic:
rw [List.getI_eq_default _ h₂]
/-- The n-th element of a `ListBlank` is well defined for all `n : ℕ`, unlike in a `List`. -/
def ListBlank.nth {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) : Γ := by
  apply l.liftOn (fun l ↦ List.getI l n)
  rintro l _ ⟨i, rfl⟩
  cases' lt_or_le n _ with h h
  · rw [List.getI_append _ _ _ h]
  rw [List.getI_eq_default _ h]
  rcases le_or_lt _ n with h₂ | h₂
  · rw [List.getI_eq_default _ h₂]
  

Proof state:
case intro.inr.inr
Γ : Type ?u.18768
inst✝ : Inhabited Γ
l✝ : ListBlank Γ
n : ℕ
l : List Γ
i : ℕ
h : List.length l ≤ n
h₂ : n < List.length (l ++ List.replicate i default)
⊢ default = List.getI (l ++ List.replicate i default) n

Next tactic:
rw [List.getI_eq_get _ h₂, List.get_append_right' h, List.get_replicate]
@[simp]
theorem ListBlank.nth_zero {Γ} [Inhabited Γ] (l : ListBlank Γ) : l.nth 0 = l.head := by
  

Proof state:
Γ : Type u_1
inst✝ : Inhabited Γ
l : ListBlank Γ
⊢ nth l 0 = head l

Next tactic:
conv => lhs; rw [← ListBlank.cons_head_tail l]
@[simp]
theorem ListBlank.nth_zero {Γ} [Inhabited Γ] (l : ListBlank Γ) : l.nth 0 = l.head := by
  conv => 

Proof state:
Γ : Type u_1
inst✝ : Inhabited Γ
l : ListBlank Γ
| nth l 0 = head l

Next tactic:
lhs; rw [← ListBlank.cons_head_tail l]
@[simp]
theorem ListBlank.nth_zero {Γ} [Inhabited Γ] (l : ListBlank Γ) : l.nth 0 = l.head := by
  conv => 

Proof state:
Γ : Type u_1
inst✝ : Inhabited Γ
l : ListBlank Γ
| nth l 0 = head l

Next tactic:
lhs
@[simp]
theorem ListBlank.nth_zero {Γ} [Inhabited Γ] (l : ListBlank Γ) : l.nth 0 = l.head := by
  conv => lhs; 

Proof state:
Γ : Type u_1
inst✝ : Inhabited Γ
l : ListBlank Γ
| nth l 0

Next tactic:
rw [← ListBlank.cons_head_tail l]
@[simp]
theorem ListBlank.nth_zero {Γ} [Inhabited Γ] (l : ListBlank Γ) : l.nth 0 = l.head := by
  conv => lhs; rw [← ListBlank.cons_head_tail l]
  

Proof state:
Γ : Type u_1
inst✝ : Inhabited Γ
l : ListBlank Γ
⊢ nth (cons (head l) (tail l)) 0 = head l

Next tactic:
exact Quotient.inductionOn' l.tail fun l ↦ rfl
@[simp]
theorem ListBlank.nth_succ {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) :
    l.nth (n + 1) = l.tail.nth n := by
  

Proof state:
Γ : Type u_1
inst✝ : Inhabited Γ
l : ListBlank Γ
n : ℕ
⊢ nth l (n + 1) = nth (tail l) n

Next tactic:
conv => lhs; rw [← ListBlank.cons_head_tail l]
@[simp]
theorem ListBlank.nth_succ {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) :
    l.nth (n + 1) = l.tail.nth n := by
  conv => 

Proof state:
Γ : Type u_1
inst✝ : Inhabited Γ
l : ListBlank Γ
n : ℕ
| nth l (n + 1) = nth (tail l) n

Next tactic:
lhs; rw [← ListBlank.cons_head_tail l]
@[simp]
theorem ListBlank.nth_succ {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) :
    l.nth (n + 1) = l.tail.nth n := by
  conv => 

Proof state:
Γ : Type u_1
inst✝ : Inhabited Γ
l : ListBlank Γ
n : ℕ
| nth l (n + 1) = nth (tail l) n

Next tactic:
lhs
@[simp]
theorem ListBlank.nth_succ {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) :
    l.nth (n + 1) = l.tail.nth n := by
  conv => lhs; 

Proof state:
Γ : Type u_1
inst✝ : Inhabited Γ
l : ListBlank Γ
n : ℕ
| nth l (n + 1)

Next tactic:
rw [← ListBlank.cons_head_tail l]
@[simp]
theorem ListBlank.nth_succ {Γ} [Inhabited Γ] (l : ListBlank Γ) (n : ℕ) :
    l.nth (n + 1) = l.tail.nth n := by
  conv => lhs; rw [← ListBlank.cons_head_tail l]
  

Proof state:
Γ : Type u_1
inst✝ : Inhabited Γ
l : ListBlank Γ
n : ℕ
⊢ nth (cons (head l) (tail l)) (n + 1) = nth (tail l) n

Next tactic:
exact Quotient.inductionOn' l.tail fun l ↦ rfl
@[ext]
theorem ListBlank.ext {Γ} [i : Inhabited Γ] {L₁ L₂ : ListBlank Γ} :
    (∀ i, L₁.nth i = L₂.nth i) → L₁ = L₂ := by
  

Proof state:
Γ : Type u_1
i : Inhabited Γ
L₁ L₂ : ListBlank Γ
⊢ (∀ (i_1 : ℕ), nth L₁ i_1 = nth L₂ i_1) → L₁ = L₂

Next tactic:
refine' ListBlank.induction_on L₁ fun l₁ ↦ ListBlank.induction_on L₂ fun l₂ H ↦ _
@[ext]
theorem ListBlank.ext {Γ} [i : Inhabited Γ] {L₁ L₂ : ListBlank Γ} :
    (∀ i, L₁.nth i = L₂.nth i) → L₁ = L₂ := by
  refine' ListBlank.induction_on L₁ fun l₁ ↦ ListBlank.induction_on L₂ fun l₂ H ↦ _
  

Proof state:
Γ : Type u_1
i : Inhabited Γ
L₁ L₂ : ListBlank Γ
l₁ l₂ : List Γ
H : ∀ (i_1 : ℕ), nth (mk l₁) i_1 = nth (mk l₂) i_1
⊢ mk l₁ = mk l₂

Next tactic:
wlog h : l₁.length ≤ l₂.length
@[ext]
theorem ListBlank.ext {Γ} [i : Inhabited Γ] {L₁ L₂ : ListBlank Γ} :
    (∀ i, L₁.nth i = L₂.nth i) → L₁ = L₂ := by
  refine' ListBlank.induction_on L₁ fun l₁ ↦ ListBlank.induction_on L₂ fun l₂ H ↦ _
  wlog h : l₁.length ≤ l₂.length
  · 

Proof state:
case inr
Γ : Type u_1
i : Inhabited Γ
L₁ L₂ : ListBlank Γ
l₁ l₂ : List Γ
H : ∀ (i_1 : ℕ), nth (mk l₁) i_1 = nth (mk l₂) i_1
this :
  ∀ {Γ : Type u_1} [i : Inhabited Γ] {L₁ L₂ : ListBlank Γ} (l₁ l₂ : List Γ),
    (∀ (i_1 : ℕ), nth (mk l₁) i_1 = nth (mk l₂) i_1) → List.length l₁ ≤ List.length l₂ → mk l₁ = mk l₂
h : ¬List.length l₁ ≤ List.length l₂
⊢ mk l₁ = mk l₂

Next tactic:
cases le_total l₁.length l₂.length <;> [skip; symm]
@[ext]
theorem ListBlank.ext {Γ} [i : Inhabited Γ] {L₁ L₂ : ListBlank Γ} :
    (∀ i, L₁.nth i = L₂.nth i) → L₁ = L₂ := by
  refine' ListBlank.induction_on L₁ fun l₁ ↦ ListBlank.induction_on L₂ fun l₂ H ↦ _
  wlog h : l₁.length ≤ l₂.length
  · 

Proof state:
case inr
Γ : Type u_1
i : Inhabited Γ
L₁ L₂ : ListBlank Γ
l₁ l₂ : List Γ
H : ∀ (i_1 : ℕ), nth (mk l₁) i_1 = nth (mk l₂) i_1
this :
  ∀ {Γ : Type u_1} [i : Inhabited Γ] {L₁ L₂ : ListBlank Γ} (l₁ l₂ : List Γ),
    (∀ (i_1 : ℕ), nth (mk l₁) i_1 = nth (mk l₂) i_1) → List.length l₁ ≤ List.length l₂ → mk l₁ = mk l₂
h : ¬List.length l₁ ≤ List.length l₂
⊢ mk l₁ = mk l₂

Next tactic:
cases le_total l₁.length l₂.length