l3lab/ntp-mathlib huggingface dataset:
/-- A recursor principle for finite types, analogous to `Nat.rec`. It effectively says
that every `Fintype` is either `Empty` or `Option α`, up to an `Equiv`. -/
def truncRecEmptyOption {P : Type u → Sort v} (of_equiv : ∀ {α β}, α ≃ β → P α → P β)
    (h_empty : P PEmpty) (h_option : ∀ {α} [Fintype α] [DecidableEq α], P α → P (Option α))
    (α : Type u) [Fintype α] [DecidableEq α] : Trunc (P α) := by
  suffices ∀ n : ℕ, Trunc (P (ULift <| Fin n)) by
    apply Trunc.bind (this (Fintype.card α))
    intro h
    apply Trunc.map _ (Fintype.truncEquivFin α)
    intro e
    exact of_equiv (Equiv.ulift.trans e.symm) h
  apply ind where
    -- porting note: do a manual recursion, instead of `induction` tactic,
    -- to ensure the result is computable
    /-- Internal induction hypothesis -/
    ind : ∀ n : ℕ, Trunc (P (ULift <| Fin n))
    | Nat.zero => by
          have : card PEmpty = card (ULift (Fin 0)) := by simp only [card_fin, card_pempty,
                                                                     card_ulift]
          apply Trunc.bind (truncEquivOfCardEq this)
          intro e
          apply Trunc.mk
          

Proof state:
case a
α✝ : Type u_1
β : Type u_2
γ : Type u_3
P : Type u → Sort v
of_equiv : {α β : Type u} → α ≃ β → P α → P β
h_empty : P PEmpty.{u + 1}
h_option : {α : Type u} → [inst : Fintype α] → [inst : DecidableEq α] → P α → P (Option α)
α : Type u
inst✝¹ : Fintype α
inst✝ : DecidableEq α
this : card PEmpty.{?u.5312 + 1} = card (ULift.{?u.5322, 0} (Fin 0))
e : PEmpty.{?u.5312 + 1} ≃ ULift.{?u.5322, 0} (Fin 0)
⊢ P (ULift.{u, 0} (Fin zero))

Next tactic:
refine' of_equiv e h_empty
/-- A recursor principle for finite types, analogous to `Nat.rec`. It effectively says
that every `Fintype` is either `Empty` or `Option α`, up to an `Equiv`. -/
def truncRecEmptyOption {P : Type u → Sort v} (of_equiv : ∀ {α β}, α ≃ β → P α → P β)
    (h_empty : P PEmpty) (h_option : ∀ {α} [Fintype α] [DecidableEq α], P α → P (Option α))
    (α : Type u) [Fintype α] [DecidableEq α] : Trunc (P α) := by
  suffices ∀ n : ℕ, Trunc (P (ULift <| Fin n)) by
    apply Trunc.bind (this (Fintype.card α))
    intro h
    apply Trunc.map _ (Fintype.truncEquivFin α)
    intro e
    exact of_equiv (Equiv.ulift.trans e.symm) h
  apply ind where
    -- porting note: do a manual recursion, instead of `induction` tactic,
    -- to ensure the result is computable
    /-- Internal induction hypothesis -/
    ind : ∀ n : ℕ, Trunc (P (ULift <| Fin n))
    | Nat.zero => by
          have : card PEmpty = card (ULift (Fin 0)) := by simp only [card_fin, card_pempty,
                                                                     card_ulift]
          apply Trunc.bind (truncEquivOfCardEq this)
          intro e
          apply Trunc.mk
          refine' of_equiv e h_empty
      | Nat.succ n => by
          

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
P : Type u → Sort v
of_equiv : {α β : Type u} → α ≃ β → P α → P β
h_empty : P PEmpty.{u + 1}
h_option : {α : Type u} → [inst : Fintype α] → [inst : DecidableEq α] → P α → P (Option α)
α : Type u
inst✝¹ : Fintype α
inst✝ : DecidableEq α
n : ℕ
⊢ Trunc (P (ULift.{u, 0} (Fin (succ n))))

Next tactic:
have : card (Option (ULift (Fin n))) = card (ULift (Fin n.succ)) := by
            simp only [card_fin, card_option, card_ulift]
/-- A recursor principle for finite types, analogous to `Nat.rec`. It effectively says
that every `Fintype` is either `Empty` or `Option α`, up to an `Equiv`. -/
def truncRecEmptyOption {P : Type u → Sort v} (of_equiv : ∀ {α β}, α ≃ β → P α → P β)
    (h_empty : P PEmpty) (h_option : ∀ {α} [Fintype α] [DecidableEq α], P α → P (Option α))
    (α : Type u) [Fintype α] [DecidableEq α] : Trunc (P α) := by
  suffices ∀ n : ℕ, Trunc (P (ULift <| Fin n)) by
    apply Trunc.bind (this (Fintype.card α))
    intro h
    apply Trunc.map _ (Fintype.truncEquivFin α)
    intro e
    exact of_equiv (Equiv.ulift.trans e.symm) h
  apply ind where
    -- porting note: do a manual recursion, instead of `induction` tactic,
    -- to ensure the result is computable
    /-- Internal induction hypothesis -/
    ind : ∀ n : ℕ, Trunc (P (ULift <| Fin n))
    | Nat.zero => by
          have : card PEmpty = card (ULift (Fin 0)) := by simp only [card_fin, card_pempty,
                                                                     card_ulift]
          apply Trunc.bind (truncEquivOfCardEq this)
          intro e
          apply Trunc.mk
          refine' of_equiv e h_empty
      | Nat.succ n => by
          have : card (Option (ULift (Fin n))) = card (ULift (Fin n.succ)) := by
            

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
P : Type u → Sort v
of_equiv : {α β : Type u} → α ≃ β → P α → P β
h_empty : P PEmpty.{u + 1}
h_option : {α : Type u} → [inst : Fintype α] → [inst : DecidableEq α] → P α → P (Option α)
α : Type u
inst✝¹ : Fintype α
inst✝ : DecidableEq α
n : ℕ
⊢ card (Option (ULift.{?u.5877, 0} (Fin n))) = card (ULift.{?u.5897, 0} (Fin (succ n)))

Next tactic:
simp only [card_fin, card_option, card_ulift]
/-- A recursor principle for finite types, analogous to `Nat.rec`. It effectively says
that every `Fintype` is either `Empty` or `Option α`, up to an `Equiv`. -/
def truncRecEmptyOption {P : Type u → Sort v} (of_equiv : ∀ {α β}, α ≃ β → P α → P β)
    (h_empty : P PEmpty) (h_option : ∀ {α} [Fintype α] [DecidableEq α], P α → P (Option α))
    (α : Type u) [Fintype α] [DecidableEq α] : Trunc (P α) := by
  suffices ∀ n : ℕ, Trunc (P (ULift <| Fin n)) by
    apply Trunc.bind (this (Fintype.card α))
    intro h
    apply Trunc.map _ (Fintype.truncEquivFin α)
    intro e
    exact of_equiv (Equiv.ulift.trans e.symm) h
  apply ind where
    -- porting note: do a manual recursion, instead of `induction` tactic,
    -- to ensure the result is computable
    /-- Internal induction hypothesis -/
    ind : ∀ n : ℕ, Trunc (P (ULift <| Fin n))
    | Nat.zero => by
          have : card PEmpty = card (ULift (Fin 0)) := by simp only [card_fin, card_pempty,
                                                                     card_ulift]
          apply Trunc.bind (truncEquivOfCardEq this)
          intro e
          apply Trunc.mk
          refine' of_equiv e h_empty
      | Nat.succ n => by
          have : card (Option (ULift (Fin n))) = card (ULift (Fin n.succ)) := by
            simp only [card_fin, card_option, card_ulift]
          

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
P : Type u → Sort v
of_equiv : {α β : Type u} → α ≃ β → P α → P β
h_empty : P PEmpty.{u + 1}
h_option : {α : Type u} → [inst : Fintype α] → [inst : DecidableEq α] → P α → P (Option α)
α : Type u
inst✝¹ : Fintype α
inst✝ : DecidableEq α
n : ℕ
this : card (Option (ULift.{?u.5877, 0} (Fin n))) = card (ULift.{?u.5897, 0} (Fin (succ n)))
⊢ Trunc (P (ULift.{u, 0} (Fin (succ n))))

Next tactic:
apply Trunc.bind (truncEquivOfCardEq this)
/-- A recursor principle for finite types, analogous to `Nat.rec`. It effectively says
that every `Fintype` is either `Empty` or `Option α`, up to an `Equiv`. -/
def truncRecEmptyOption {P : Type u → Sort v} (of_equiv : ∀ {α β}, α ≃ β → P α → P β)
    (h_empty : P PEmpty) (h_option : ∀ {α} [Fintype α] [DecidableEq α], P α → P (Option α))
    (α : Type u) [Fintype α] [DecidableEq α] : Trunc (P α) := by
  suffices ∀ n : ℕ, Trunc (P (ULift <| Fin n)) by
    apply Trunc.bind (this (Fintype.card α))
    intro h
    apply Trunc.map _ (Fintype.truncEquivFin α)
    intro e
    exact of_equiv (Equiv.ulift.trans e.symm) h
  apply ind where
    -- porting note: do a manual recursion, instead of `induction` tactic,
    -- to ensure the result is computable
    /-- Internal induction hypothesis -/
    ind : ∀ n : ℕ, Trunc (P (ULift <| Fin n))
    | Nat.zero => by
          have : card PEmpty = card (ULift (Fin 0)) := by simp only [card_fin, card_pempty,
                                                                     card_ulift]
          apply Trunc.bind (truncEquivOfCardEq this)
          intro e
          apply Trunc.mk
          refine' of_equiv e h_empty
      | Nat.succ n => by
          have : card (Option (ULift (Fin n))) = card (ULift (Fin n.succ)) := by
            simp only [card_fin, card_option, card_ulift]
          apply Trunc.bind (truncEquivOfCardEq this)
          

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
P : Type u → Sort v
of_equiv : {α β : Type u} → α ≃ β → P α → P β
h_empty : P PEmpty.{u + 1}
h_option : {α : Type u} → [inst : Fintype α] → [inst : DecidableEq α] → P α → P (Option α)
α : Type u
inst✝¹ : Fintype α
inst✝ : DecidableEq α
n : ℕ
this : card (Option (ULift.{?u.5877, 0} (Fin n))) = card (ULift.{?u.5897, 0} (Fin (succ n)))
⊢ Option (ULift.{?u.5877, 0} (Fin n)) ≃ ULift.{?u.5897, 0} (Fin (succ n)) → Trunc (P (ULift.{u, 0} (Fin (succ n))))

Next tactic:
intro e
/-- A recursor principle for finite types, analogous to `Nat.rec`. It effectively says
that every `Fintype` is either `Empty` or `Option α`, up to an `Equiv`. -/
def truncRecEmptyOption {P : Type u → Sort v} (of_equiv : ∀ {α β}, α ≃ β → P α → P β)
    (h_empty : P PEmpty) (h_option : ∀ {α} [Fintype α] [DecidableEq α], P α → P (Option α))
    (α : Type u) [Fintype α] [DecidableEq α] : Trunc (P α) := by
  suffices ∀ n : ℕ, Trunc (P (ULift <| Fin n)) by
    apply Trunc.bind (this (Fintype.card α))
    intro h
    apply Trunc.map _ (Fintype.truncEquivFin α)
    intro e
    exact of_equiv (Equiv.ulift.trans e.symm) h
  apply ind where
    -- porting note: do a manual recursion, instead of `induction` tactic,
    -- to ensure the result is computable
    /-- Internal induction hypothesis -/
    ind : ∀ n : ℕ, Trunc (P (ULift <| Fin n))
    | Nat.zero => by
          have : card PEmpty = card (ULift (Fin 0)) := by simp only [card_fin, card_pempty,
                                                                     card_ulift]
          apply Trunc.bind (truncEquivOfCardEq this)
          intro e
          apply Trunc.mk
          refine' of_equiv e h_empty
      | Nat.succ n => by
          have : card (Option (ULift (Fin n))) = card (ULift (Fin n.succ)) := by
            simp only [card_fin, card_option, card_ulift]
          apply Trunc.bind (truncEquivOfCardEq this)
          intro e
          

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
P : Type u → Sort v
of_equiv : {α β : Type u} → α ≃ β → P α → P β
h_empty : P PEmpty.{u + 1}
h_option : {α : Type u} → [inst : Fintype α] → [inst : DecidableEq α] → P α → P (Option α)
α : Type u
inst✝¹ : Fintype α
inst✝ : DecidableEq α
n : ℕ
this : card (Option (ULift.{?u.5877, 0} (Fin n))) = card (ULift.{?u.5897, 0} (Fin (succ n)))
e : Option (ULift.{?u.5877, 0} (Fin n)) ≃ ULift.{?u.5897, 0} (Fin (succ n))
⊢ Trunc (P (ULift.{u, 0} (Fin (succ n))))

Next tactic:
apply Trunc.map _ (ind n)
/-- A recursor principle for finite types, analogous to `Nat.rec`. It effectively says
that every `Fintype` is either `Empty` or `Option α`, up to an `Equiv`. -/
def truncRecEmptyOption {P : Type u → Sort v} (of_equiv : ∀ {α β}, α ≃ β → P α → P β)
    (h_empty : P PEmpty) (h_option : ∀ {α} [Fintype α] [DecidableEq α], P α → P (Option α))
    (α : Type u) [Fintype α] [DecidableEq α] : Trunc (P α) := by
  suffices ∀ n : ℕ, Trunc (P (ULift <| Fin n)) by
    apply Trunc.bind (this (Fintype.card α))
    intro h
    apply Trunc.map _ (Fintype.truncEquivFin α)
    intro e
    exact of_equiv (Equiv.ulift.trans e.symm) h
  apply ind where
    -- porting note: do a manual recursion, instead of `induction` tactic,
    -- to ensure the result is computable
    /-- Internal induction hypothesis -/
    ind : ∀ n : ℕ, Trunc (P (ULift <| Fin n))
    | Nat.zero => by
          have : card PEmpty = card (ULift (Fin 0)) := by simp only [card_fin, card_pempty,
                                                                     card_ulift]
          apply Trunc.bind (truncEquivOfCardEq this)
          intro e
          apply Trunc.mk
          refine' of_equiv e h_empty
      | Nat.succ n => by
          have : card (Option (ULift (Fin n))) = card (ULift (Fin n.succ)) := by
            simp only [card_fin, card_option, card_ulift]
          apply Trunc.bind (truncEquivOfCardEq this)
          intro e
          apply Trunc.map _ (ind n)
          

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
P : Type u → Sort v
of_equiv : {α β : Type u} → α ≃ β → P α → P β
h_empty : P PEmpty.{u + 1}
h_option : {α : Type u} → [inst : Fintype α] → [inst : DecidableEq α] → P α → P (Option α)
α : Type u
inst✝¹ : Fintype α
inst✝ : DecidableEq α
n : ℕ
this : card (Option (ULift.{?u.5877, 0} (Fin n))) = card (ULift.{?u.5897, 0} (Fin (succ n)))
e : Option (ULift.{?u.5877, 0} (Fin n)) ≃ ULift.{?u.5897, 0} (Fin (succ n))
⊢ P (ULift.{u, 0} (Fin n)) → P (ULift.{u, 0} (Fin (succ n)))

Next tactic:
intro ih
/-- A recursor principle for finite types, analogous to `Nat.rec`. It effectively says
that every `Fintype` is either `Empty` or `Option α`, up to an `Equiv`. -/
def truncRecEmptyOption {P : Type u → Sort v} (of_equiv : ∀ {α β}, α ≃ β → P α → P β)
    (h_empty : P PEmpty) (h_option : ∀ {α} [Fintype α] [DecidableEq α], P α → P (Option α))
    (α : Type u) [Fintype α] [DecidableEq α] : Trunc (P α) := by
  suffices ∀ n : ℕ, Trunc (P (ULift <| Fin n)) by
    apply Trunc.bind (this (Fintype.card α))
    intro h
    apply Trunc.map _ (Fintype.truncEquivFin α)
    intro e
    exact of_equiv (Equiv.ulift.trans e.symm) h
  apply ind where
    -- porting note: do a manual recursion, instead of `induction` tactic,
    -- to ensure the result is computable
    /-- Internal induction hypothesis -/
    ind : ∀ n : ℕ, Trunc (P (ULift <| Fin n))
    | Nat.zero => by
          have : card PEmpty = card (ULift (Fin 0)) := by simp only [card_fin, card_pempty,
                                                                     card_ulift]
          apply Trunc.bind (truncEquivOfCardEq this)
          intro e
          apply Trunc.mk
          refine' of_equiv e h_empty
      | Nat.succ n => by
          have : card (Option (ULift (Fin n))) = card (ULift (Fin n.succ)) := by
            simp only [card_fin, card_option, card_ulift]
          apply Trunc.bind (truncEquivOfCardEq this)
          intro e
          apply Trunc.map _ (ind n)
          intro ih
          

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
P : Type u → Sort v
of_equiv : {α β : Type u} → α ≃ β → P α → P β
h_empty : P PEmpty.{u + 1}
h_option : {α : Type u} → [inst : Fintype α] → [inst : DecidableEq α] → P α → P (Option α)
α : Type u
inst✝¹ : Fintype α
inst✝ : DecidableEq α
n : ℕ
this : card (Option (ULift.{?u.5877, 0} (Fin n))) = card (ULift.{?u.5897, 0} (Fin (succ n)))
e : Option (ULift.{?u.5877, 0} (Fin n)) ≃ ULift.{?u.5897, 0} (Fin (succ n))
ih : P (ULift.{u, 0} (Fin n))
⊢ P (ULift.{u, 0} (Fin (succ n)))

Next tactic:
refine' of_equiv e (h_option ih)
/-- A recursor principle for finite types, analogous to `Nat.rec`. It effectively says
that every `Fintype` is either `Empty` or `Option α`, up to an `Equiv`. -/
def truncRecEmptyOption {P : Type u → Sort v} (of_equiv : ∀ {α β}, α ≃ β → P α → P β)
    (h_empty : P PEmpty) (h_option : ∀ {α} [Fintype α] [DecidableEq α], P α → P (Option α))
    (α : Type u) [Fintype α] [DecidableEq α] : Trunc (P α) := by
  

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
P : Type u → Sort v
of_equiv : {α β : Type u} → α ≃ β → P α → P β
h_empty : P PEmpty.{u + 1}
h_option : {α : Type u} → [inst : Fintype α] → [inst : DecidableEq α] → P α → P (Option α)
α : Type u
inst✝¹ : Fintype α
inst✝ : DecidableEq α
⊢ Trunc (P α)

Next tactic:
suffices ∀ n : ℕ, Trunc (P (ULift <| Fin n)) by
    apply Trunc.bind (this (Fintype.card α))
    intro h
    apply Trunc.map _ (Fintype.truncEquivFin α)
    intro e
    exact of_equiv (Equiv.ulift.trans e.symm) h
/-- A recursor principle for finite types, analogous to `Nat.rec`. It effectively says
that every `Fintype` is either `Empty` or `Option α`, up to an `Equiv`. -/
def truncRecEmptyOption {P : Type u → Sort v} (of_equiv : ∀ {α β}, α ≃ β → P α → P β)
    (h_empty : P PEmpty) (h_option : ∀ {α} [Fintype α] [DecidableEq α], P α → P (Option α))
    (α : Type u) [Fintype α] [DecidableEq α] : Trunc (P α) := by
  suffices ∀ n : ℕ, Trunc (P (ULift <| Fin n)) by
    

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
P : Type u → Sort v
of_equiv : {α β : Type u} → α ≃ β → P α → P β
h_empty : P PEmpty.{u + 1}
h_option : {α : Type u} → [inst : Fintype α] → [inst : DecidableEq α] → P α → P (Option α)
α : Type u
inst✝¹ : Fintype α
inst✝ : DecidableEq α
this : (n : ℕ) → Trunc (P (ULift.{u, 0} (Fin n)))
⊢ Trunc (P α)

Next tactic:
apply Trunc.bind (this (Fintype.card α))
/-- A recursor principle for finite types, analogous to `Nat.rec`. It effectively says
that every `Fintype` is either `Empty` or `Option α`, up to an `Equiv`. -/
def truncRecEmptyOption {P : Type u → Sort v} (of_equiv : ∀ {α β}, α ≃ β → P α → P β)
    (h_empty : P PEmpty) (h_option : ∀ {α} [Fintype α] [DecidableEq α], P α → P (Option α))
    (α : Type u) [Fintype α] [DecidableEq α] : Trunc (P α) := by
  suffices ∀ n : ℕ, Trunc (P (ULift <| Fin n)) by
    apply Trunc.bind (this (Fintype.card α))
    

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
P : Type u → Sort v
of_equiv : {α β : Type u} → α ≃ β → P α → P β
h_empty : P PEmpty.{u + 1}
h_option : {α : Type u} → [inst : Fintype α] → [inst : DecidableEq α] → P α → P (Option α)
α : Type u
inst✝¹ : Fintype α
inst✝ : DecidableEq α
this : (n : ℕ) → Trunc (P (ULift.{u, 0} (Fin n)))
⊢ P (ULift.{u, 0} (Fin (card α))) → Trunc (P α)

Next tactic:
intro h
/-- A recursor principle for finite types, analogous to `Nat.rec`. It effectively says
that every `Fintype` is either `Empty` or `Option α`, up to an `Equiv`. -/
def truncRecEmptyOption {P : Type u → Sort v} (of_equiv : ∀ {α β}, α ≃ β → P α → P β)
    (h_empty : P PEmpty) (h_option : ∀ {α} [Fintype α] [DecidableEq α], P α → P (Option α))
    (α : Type u) [Fintype α] [DecidableEq α] : Trunc (P α) := by
  suffices ∀ n : ℕ, Trunc (P (ULift <| Fin n)) by
    apply Trunc.bind (this (Fintype.card α))
    intro h
    

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
P : Type u → Sort v
of_equiv : {α β : Type u} → α ≃ β → P α → P β
h_empty : P PEmpty.{u + 1}
h_option : {α : Type u} → [inst : Fintype α] → [inst : DecidableEq α] → P α → P (Option α)
α : Type u
inst✝¹ : Fintype α
inst✝ : DecidableEq α
this : (n : ℕ) → Trunc (P (ULift.{u, 0} (Fin n)))
h : P (ULift.{u, 0} (Fin (card α)))
⊢ Trunc (P α)

Next tactic:
apply Trunc.map _ (Fintype.truncEquivFin α)
/-- A recursor principle for finite types, analogous to `Nat.rec`. It effectively says
that every `Fintype` is either `Empty` or `Option α`, up to an `Equiv`. -/
def truncRecEmptyOption {P : Type u → Sort v} (of_equiv : ∀ {α β}, α ≃ β → P α → P β)
    (h_empty : P PEmpty) (h_option : ∀ {α} [Fintype α] [DecidableEq α], P α → P (Option α))
    (α : Type u) [Fintype α] [DecidableEq α] : Trunc (P α) := by
  suffices ∀ n : ℕ, Trunc (P (ULift <| Fin n)) by
    apply Trunc.bind (this (Fintype.card α))
    intro h
    apply Trunc.map _ (Fintype.truncEquivFin α)
    

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
P : Type u → Sort v
of_equiv : {α β : Type u} → α ≃ β → P α → P β
h_empty : P PEmpty.{u + 1}
h_option : {α : Type u} → [inst : Fintype α] → [inst : DecidableEq α] → P α → P (Option α)
α : Type u
inst✝¹ : Fintype α
inst✝ : DecidableEq α
this : (n : ℕ) → Trunc (P (ULift.{u, 0} (Fin n)))
h : P (ULift.{u, 0} (Fin (card α)))
⊢ α ≃ Fin (card α) → P α

Next tactic:
intro e
/-- A recursor principle for finite types, analogous to `Nat.rec`. It effectively says
that every `Fintype` is either `Empty` or `Option α`, up to an `Equiv`. -/
def truncRecEmptyOption {P : Type u → Sort v} (of_equiv : ∀ {α β}, α ≃ β → P α → P β)
    (h_empty : P PEmpty) (h_option : ∀ {α} [Fintype α] [DecidableEq α], P α → P (Option α))
    (α : Type u) [Fintype α] [DecidableEq α] : Trunc (P α) := by
  suffices ∀ n : ℕ, Trunc (P (ULift <| Fin n)) by
    apply Trunc.bind (this (Fintype.card α))
    intro h
    apply Trunc.map _ (Fintype.truncEquivFin α)
    intro e
    

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
P : Type u → Sort v
of_equiv : {α β : Type u} → α ≃ β → P α → P β
h_empty : P PEmpty.{u + 1}
h_option : {α : Type u} → [inst : Fintype α] → [inst : DecidableEq α] → P α → P (Option α)
α : Type u
inst✝¹ : Fintype α
inst✝ : DecidableEq α
this : (n : ℕ) → Trunc (P (ULift.{u, 0} (Fin n)))
h : P (ULift.{u, 0} (Fin (card α)))
e : α ≃ Fin (card α)
⊢ P α

Next tactic:
exact of_equiv (Equiv.ulift.trans e.symm) h
/-- A recursor principle for finite types, analogous to `Nat.rec`. It effectively says
that every `Fintype` is either `Empty` or `Option α`, up to an `Equiv`. -/
def truncRecEmptyOption {P : Type u → Sort v} (of_equiv : ∀ {α β}, α ≃ β → P α → P β)
    (h_empty : P PEmpty) (h_option : ∀ {α} [Fintype α] [DecidableEq α], P α → P (Option α))
    (α : Type u) [Fintype α] [DecidableEq α] : Trunc (P α) := by
  suffices ∀ n : ℕ, Trunc (P (ULift <| Fin n)) by
    apply Trunc.bind (this (Fintype.card α))
    intro h
    apply Trunc.map _ (Fintype.truncEquivFin α)
    intro e
    exact of_equiv (Equiv.ulift.trans e.symm) h
  

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
P : Type u → Sort v
of_equiv : {α β : Type u} → α ≃ β → P α → P β
h_empty : P PEmpty.{u + 1}
h_option : {α : Type u} → [inst : Fintype α] → [inst : DecidableEq α] → P α → P (Option α)
α : Type u
inst✝¹ : Fintype α
inst✝ : DecidableEq α
⊢ (n : ℕ) → Trunc (P (ULift.{u, 0} (Fin n)))

Next tactic:
apply ind
/-- An induction principle for finite types, analogous to `Nat.rec`. It effectively says
that every `Fintype` is either `Empty` or `Option α`, up to an `Equiv`. -/
@[elab_as_elim]
theorem induction_empty_option {P : ∀ (α : Type u) [Fintype α], Prop}
    (of_equiv : ∀ (α β) [Fintype β] (e : α ≃ β), @P α (@Fintype.ofEquiv α β ‹_› e.symm) → @P β ‹_›)
    (h_empty : P PEmpty) (h_option : ∀ (α) [Fintype α], P α → P (Option α)) (α : Type u)
    [h_fintype : Fintype α] : P α := by
  

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
P : (α : Type u) → [inst : Fintype α] → Prop
of_equiv : ∀ (α β : Type u) [inst : Fintype β] (e : α ≃ β), P α → P β
h_empty : P PEmpty.{u + 1}
h_option : ∀ (α : Type u) [inst : Fintype α], P α → P (Option α)
α : Type u
h_fintype : Fintype α
⊢ P α

Next tactic:
obtain ⟨p⟩ :=
    let f_empty := fun i => by convert h_empty
    let h_option : ∀ {α : Type u} [Fintype α] [DecidableEq α],
          (∀ (h : Fintype α), P α) → ∀ (h : Fintype (Option α)), P (Option α)  := by
      rintro α hα - Pα hα'
      convert h_option α (Pα _)
    @truncRecEmptyOption (fun α => ∀ h, @P α h) (@fun α β e hα hβ => @of_equiv α β hβ e (hα _))
      f_empty h_option α _ (Classical.decEq α)
/-- An induction principle for finite types, analogous to `Nat.rec`. It effectively says
that every `Fintype` is either `Empty` or `Option α`, up to an `Equiv`. -/
@[elab_as_elim]
theorem induction_empty_option {P : ∀ (α : Type u) [Fintype α], Prop}
    (of_equiv : ∀ (α β) [Fintype β] (e : α ≃ β), @P α (@Fintype.ofEquiv α β ‹_› e.symm) → @P β ‹_›)
    (h_empty : P PEmpty) (h_option : ∀ (α) [Fintype α], P α → P (Option α)) (α : Type u)
    [h_fintype : Fintype α] : P α := by
  obtain ⟨p⟩ :=
    let f_empty := fun i => by 

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
P : (α : Type u) → [inst : Fintype α] → Prop
of_equiv : ∀ (α β : Type u) [inst : Fintype β] (e : α ≃ β), P α → P β
h_empty : P PEmpty.{u + 1}
h_option : ∀ (α : Type u) [inst : Fintype α], P α → P (Option α)
α : Type u
h_fintype : Fintype α
i : Fintype PEmpty.{u + 1}
⊢ P PEmpty.{u + 1}

Next tactic:
convert h_empty