l3lab/ntp-mathlib huggingface dataset:
/-- If `C` has finite coproducts and filtered colimits, we can construct arbitrary coproducts by
    taking the colimit of the diagram formed by the coproducts of finite sets over the indexing
    type. -/
@[simps!]
def liftToFinsetColimitCocone [HasFiniteCoproducts C] [HasFilteredColimitsOfSize.{w, w} C]
    (F : Discrete α ⥤ C) : ColimitCocone F where
  cocone :=
    { pt := colimit (liftToFinset F)
      ι :=
        Discrete.natTrans fun j =>
          @Sigma.ι _ _ _ (fun x : ({j} : Finset (Discrete α)) => F.obj x) _ ⟨j, by simp⟩ ≫
            colimit.ι (liftToFinset F) {j} }
  isColimit :=
    { desc := fun s =>
        colimit.desc (liftToFinset F)
          { pt := s.pt
            ι := { app := fun t => Sigma.desc fun x => s.ι.app x } }
      uniq := fun s m h => by
        apply colimit.hom_ext
        rintro t
        dsimp [liftToFinset]
        

Proof state:
case w
C : Type u
inst✝² : Category.{v, u} C
α : Type w
inst✝¹ : HasFiniteCoproducts C
inst✝ : HasFilteredColimitsOfSize.{w, w, v, u} C
F : Discrete α ⥤ C
s : Cocone F
m :
  { pt := colimit (liftToFinset F),
        ι :=
          Discrete.natTrans fun j =>
            Sigma.ι (fun x => F.obj ↑x) { val := j, property := (_ : j ∈ {j}) } ≫ colimit.ι (liftToFinset F) {j} }.pt ⟶
    s.pt
h :
  ∀ (j : Discrete α),
    { pt := colimit (liftToFinset F),
                ι :=
                  Discrete.natTrans fun j =>
                    Sigma.ι (fun x => F.obj ↑x) { val := j, property := (_ : j ∈ {j}) } ≫
                      colimit.ι (liftToFinset F) {j} }.ι.app
          j ≫
        m =
      s.ι.app j
t : Finset (Discrete α)
⊢ colimit.ι
        (Functor.mk
          { obj := fun s => ∐ fun x => F.obj ↑x,
            map := fun {x Y} h =>
              Sigma.desc fun y => Sigma.ι (fun x => F.obj ↑x) { val := ↑y, property := (_ : ↑y ∈ Y) } })
        t ≫
      m =
    colimit.ι
        (Functor.mk
          { obj := fun s => ∐ fun x => F.obj ↑x,
            map := fun {x Y} h =>
              Sigma.desc fun y => Sigma.ι (fun x => F.obj ↑x) { val := ↑y, property := (_ : ↑y ∈ Y) } })
        t ≫
      colimit.desc
        (Functor.mk
          { obj := fun s => ∐ fun x => F.obj ↑x,
            map := fun {x Y} h =>
              Sigma.desc fun y => Sigma.ι (fun x => F.obj ↑x) { val := ↑y, property := (_ : ↑y ∈ Y) } })
        { pt := s.pt, ι := NatTrans.mk fun t => Sigma.desc fun x => s.ι.app ↑x }

Next tactic:
apply colimit.hom_ext
/-- If `C` has finite coproducts and filtered colimits, we can construct arbitrary coproducts by
    taking the colimit of the diagram formed by the coproducts of finite sets over the indexing
    type. -/
@[simps!]
def liftToFinsetColimitCocone [HasFiniteCoproducts C] [HasFilteredColimitsOfSize.{w, w} C]
    (F : Discrete α ⥤ C) : ColimitCocone F where
  cocone :=
    { pt := colimit (liftToFinset F)
      ι :=
        Discrete.natTrans fun j =>
          @Sigma.ι _ _ _ (fun x : ({j} : Finset (Discrete α)) => F.obj x) _ ⟨j, by simp⟩ ≫
            colimit.ι (liftToFinset F) {j} }
  isColimit :=
    { desc := fun s =>
        colimit.desc (liftToFinset F)
          { pt := s.pt
            ι := { app := fun t => Sigma.desc fun x => s.ι.app x } }
      uniq := fun s m h => by
        apply colimit.hom_ext
        rintro t
        dsimp [liftToFinset]
        apply colimit.hom_ext
        

Proof state:
case w.w
C : Type u
inst✝² : Category.{v, u} C
α : Type w
inst✝¹ : HasFiniteCoproducts C
inst✝ : HasFilteredColimitsOfSize.{w, w, v, u} C
F : Discrete α ⥤ C
s : Cocone F
m :
  { pt := colimit (liftToFinset F),
        ι :=
          Discrete.natTrans fun j =>
            Sigma.ι (fun x => F.obj ↑x) { val := j, property := (_ : j ∈ {j}) } ≫ colimit.ι (liftToFinset F) {j} }.pt ⟶
    s.pt
h :
  ∀ (j : Discrete α),
    { pt := colimit (liftToFinset F),
                ι :=
                  Discrete.natTrans fun j =>
                    Sigma.ι (fun x => F.obj ↑x) { val := j, property := (_ : j ∈ {j}) } ≫
                      colimit.ι (liftToFinset F) {j} }.ι.app
          j ≫
        m =
      s.ι.app j
t : Finset (Discrete α)
⊢ ∀ (j : Discrete { x // x ∈ t }),
    colimit.ι (Discrete.functor fun x => F.obj ↑x) j ≫
        colimit.ι
            (Functor.mk
              { obj := fun s => ∐ fun x => F.obj ↑x,
                map := fun {x Y} h =>
                  Sigma.desc fun y => Sigma.ι (fun x => F.obj ↑x) { val := ↑y, property := (_ : ↑y ∈ Y) } })
            t ≫
          m =
      colimit.ι (Discrete.functor fun x => F.obj ↑x) j ≫
        colimit.ι
            (Functor.mk
              { obj := fun s => ∐ fun x => F.obj ↑x,
                map := fun {x Y} h =>
                  Sigma.desc fun y => Sigma.ι (fun x => F.obj ↑x) { val := ↑y, property := (_ : ↑y ∈ Y) } })
            t ≫
          colimit.desc
            (Functor.mk
              { obj := fun s => ∐ fun x => F.obj ↑x,
                map := fun {x Y} h =>
                  Sigma.desc fun y => Sigma.ι (fun x => F.obj ↑x) { val := ↑y, property := (_ : ↑y ∈ Y) } })
            { pt := s.pt, ι := NatTrans.mk fun t => Sigma.desc fun x => s.ι.app ↑x }

Next tactic:
rintro ⟨⟨j, hj⟩⟩
/-- If `C` has finite coproducts and filtered colimits, we can construct arbitrary coproducts by
    taking the colimit of the diagram formed by the coproducts of finite sets over the indexing
    type. -/
@[simps!]
def liftToFinsetColimitCocone [HasFiniteCoproducts C] [HasFilteredColimitsOfSize.{w, w} C]
    (F : Discrete α ⥤ C) : ColimitCocone F where
  cocone :=
    { pt := colimit (liftToFinset F)
      ι :=
        Discrete.natTrans fun j =>
          @Sigma.ι _ _ _ (fun x : ({j} : Finset (Discrete α)) => F.obj x) _ ⟨j, by simp⟩ ≫
            colimit.ι (liftToFinset F) {j} }
  isColimit :=
    { desc := fun s =>
        colimit.desc (liftToFinset F)
          { pt := s.pt
            ι := { app := fun t => Sigma.desc fun x => s.ι.app x } }
      uniq := fun s m h => by
        apply colimit.hom_ext
        rintro t
        dsimp [liftToFinset]
        apply colimit.hom_ext
        rintro ⟨⟨j, hj⟩⟩
        

Proof state:
case w.w.mk.mk
C : Type u
inst✝² : Category.{v, u} C
α : Type w
inst✝¹ : HasFiniteCoproducts C
inst✝ : HasFilteredColimitsOfSize.{w, w, v, u} C
F : Discrete α ⥤ C
s : Cocone F
m :
  { pt := colimit (liftToFinset F),
        ι :=
          Discrete.natTrans fun j =>
            Sigma.ι (fun x => F.obj ↑x) { val := j, property := (_ : j ∈ {j}) } ≫ colimit.ι (liftToFinset F) {j} }.pt ⟶
    s.pt
h :
  ∀ (j : Discrete α),
    { pt := colimit (liftToFinset F),
                ι :=
                  Discrete.natTrans fun j =>
                    Sigma.ι (fun x => F.obj ↑x) { val := j, property := (_ : j ∈ {j}) } ≫
                      colimit.ι (liftToFinset F) {j} }.ι.app
          j ≫
        m =
      s.ι.app j
t : Finset (Discrete α)
j : Discrete α
hj : j ∈ t
⊢ colimit.ι (Discrete.functor fun x => F.obj ↑x) { as := { val := j, property := hj } } ≫
      colimit.ι
          (Functor.mk
            { obj := fun s => ∐ fun x => F.obj ↑x,
              map := fun {x Y} h =>
                Sigma.desc fun y => Sigma.ι (fun x => F.obj ↑x) { val := ↑y, property := (_ : ↑y ∈ Y) } })
          t ≫
        m =
    colimit.ι (Discrete.functor fun x => F.obj ↑x) { as := { val := j, property := hj } } ≫
      colimit.ι
          (Functor.mk
            { obj := fun s => ∐ fun x => F.obj ↑x,
              map := fun {x Y} h =>
                Sigma.desc fun y => Sigma.ι (fun x => F.obj ↑x) { val := ↑y, property := (_ : ↑y ∈ Y) } })
          t ≫
        colimit.desc
          (Functor.mk
            { obj := fun s => ∐ fun x => F.obj ↑x,
              map := fun {x Y} h =>
                Sigma.desc fun y => Sigma.ι (fun x => F.obj ↑x) { val := ↑y, property := (_ : ↑y ∈ Y) } })
          { pt := s.pt, ι := NatTrans.mk fun t => Sigma.desc fun x => s.ι.app ↑x }

Next tactic:
convert h j using 1
/-- If `C` has finite coproducts and filtered colimits, we can construct arbitrary coproducts by
    taking the colimit of the diagram formed by the coproducts of finite sets over the indexing
    type. -/
@[simps!]
def liftToFinsetColimitCocone [HasFiniteCoproducts C] [HasFilteredColimitsOfSize.{w, w} C]
    (F : Discrete α ⥤ C) : ColimitCocone F where
  cocone :=
    { pt := colimit (liftToFinset F)
      ι :=
        Discrete.natTrans fun j =>
          @Sigma.ι _ _ _ (fun x : ({j} : Finset (Discrete α)) => F.obj x) _ ⟨j, by simp⟩ ≫
            colimit.ι (liftToFinset F) {j} }
  isColimit :=
    { desc := fun s =>
        colimit.desc (liftToFinset F)
          { pt := s.pt
            ι := { app := fun t => Sigma.desc fun x => s.ι.app x } }
      uniq := fun s m h => by
        apply colimit.hom_ext
        rintro t
        dsimp [liftToFinset]
        apply colimit.hom_ext
        rintro ⟨⟨j, hj⟩⟩
        convert h j using 1
        · 

Proof state:
case h.e'_2.h
C : Type u
inst✝² : Category.{v, u} C
α : Type w
inst✝¹ : HasFiniteCoproducts C
inst✝ : HasFilteredColimitsOfSize.{w, w, v, u} C
F : Discrete α ⥤ C
s : Cocone F
m :
  { pt := colimit (liftToFinset F),
        ι :=
          Discrete.natTrans fun j =>
            Sigma.ι (fun x => F.obj ↑x) { val := j, property := (_ : j ∈ {j}) } ≫ colimit.ι (liftToFinset F) {j} }.pt ⟶
    s.pt
h :
  ∀ (j : Discrete α),
    { pt := colimit (liftToFinset F),
                ι :=
                  Discrete.natTrans fun j =>
                    Sigma.ι (fun x => F.obj ↑x) { val := j, property := (_ : j ∈ {j}) } ≫
                      colimit.ι (liftToFinset F) {j} }.ι.app
          j ≫
        m =
      s.ι.app j
t : Finset (Discrete α)
j : Discrete α
hj : j ∈ t
e_1✝ : ((Discrete.functor fun x => F.obj ↑x).obj { as := { val := j, property := hj } } ⟶ s.pt) = (F.obj j ⟶ s.pt)
⊢ colimit.ι (Discrete.functor fun x => F.obj ↑x) { as := { val := j, property := hj } } ≫
      colimit.ι
          (Functor.mk
            { obj := fun s => ∐ fun x => F.obj ↑x,
              map := fun {x Y} h =>
                Sigma.desc fun y => Sigma.ι (fun x => F.obj ↑x) { val := ↑y, property := (_ : ↑y ∈ Y) } })
          t ≫
        m =
    { pt := colimit (liftToFinset F),
              ι :=
                Discrete.natTrans fun j =>
                  Sigma.ι (fun x => F.obj ↑x) { val := j, property := (_ : j ∈ {j}) } ≫
                    colimit.ι (liftToFinset F) {j} }.ι.app
        j ≫
      m

Next tactic:
simp [← colimit.w (liftToFinset F) ⟨⟨Finset.singleton_subset_iff.2 hj⟩⟩]
/-- If `C` has finite coproducts and filtered colimits, we can construct arbitrary coproducts by
    taking the colimit of the diagram formed by the coproducts of finite sets over the indexing
    type. -/
@[simps!]
def liftToFinsetColimitCocone [HasFiniteCoproducts C] [HasFilteredColimitsOfSize.{w, w} C]
    (F : Discrete α ⥤ C) : ColimitCocone F where
  cocone :=
    { pt := colimit (liftToFinset F)
      ι :=
        Discrete.natTrans fun j =>
          @Sigma.ι _ _ _ (fun x : ({j} : Finset (Discrete α)) => F.obj x) _ ⟨j, by simp⟩ ≫
            colimit.ι (liftToFinset F) {j} }
  isColimit :=
    { desc := fun s =>
        colimit.desc (liftToFinset F)
          { pt := s.pt
            ι := { app := fun t => Sigma.desc fun x => s.ι.app x } }
      uniq := fun s m h => by
        apply colimit.hom_ext
        rintro t
        dsimp [liftToFinset]
        apply colimit.hom_ext
        rintro ⟨⟨j, hj⟩⟩
        convert h j using 1
        · simp [← colimit.w (liftToFinset F) ⟨⟨Finset.singleton_subset_iff.2 hj⟩⟩]
          

Proof state:
case h.e'_2.h
C : Type u
inst✝² : Category.{v, u} C
α : Type w
inst✝¹ : HasFiniteCoproducts C
inst✝ : HasFilteredColimitsOfSize.{w, w, v, u} C
F : Discrete α ⥤ C
s : Cocone F
m :
  { pt := colimit (liftToFinset F),
        ι :=
          Discrete.natTrans fun j =>
            Sigma.ι (fun x => F.obj ↑x) { val := j, property := (_ : j ∈ {j}) } ≫ colimit.ι (liftToFinset F) {j} }.pt ⟶
    s.pt
h :
  ∀ (j : Discrete α),
    { pt := colimit (liftToFinset F),
                ι :=
                  Discrete.natTrans fun j =>
                    Sigma.ι (fun x => F.obj ↑x) { val := j, property := (_ : j ∈ {j}) } ≫
                      colimit.ι (liftToFinset F) {j} }.ι.app
          j ≫
        m =
      s.ι.app j
t : Finset (Discrete α)
j : Discrete α
hj : j ∈ t
e_1✝ : ((Discrete.functor fun x => F.obj ↑x).obj { as := { val := j, property := hj } } ⟶ s.pt) = (F.obj j ⟶ s.pt)
⊢ colimit.ι (Discrete.functor fun x => F.obj ↑x) { as := { val := j, property := hj } } ≫
      colimit.ι
          (Functor.mk
            { obj := fun s => ∐ fun x => F.obj ↑x,
              map := fun {x Y} h =>
                Sigma.desc fun y => Sigma.ι (fun x => F.obj ↑x) { val := ↑y, property := (_ : ↑y ∈ Y) } })
          t ≫
        m =
    Sigma.ι (fun x => F.obj ↑x) { val := j, property := (_ : ↑{ val := j, property := (_ : j ∈ {j}) } ∈ t) } ≫
      colimit.ι (liftToFinset F) t ≫ m

Next tactic:
rfl
/-- If `C` has finite coproducts and filtered colimits, we can construct arbitrary coproducts by
    taking the colimit of the diagram formed by the coproducts of finite sets over the indexing
    type. -/
@[simps!]
def liftToFinsetColimitCocone [HasFiniteCoproducts C] [HasFilteredColimitsOfSize.{w, w} C]
    (F : Discrete α ⥤ C) : ColimitCocone F where
  cocone :=
    { pt := colimit (liftToFinset F)
      ι :=
        Discrete.natTrans fun j =>
          @Sigma.ι _ _ _ (fun x : ({j} : Finset (Discrete α)) => F.obj x) _ ⟨j, by simp⟩ ≫
            colimit.ι (liftToFinset F) {j} }
  isColimit :=
    { desc := fun s =>
        colimit.desc (liftToFinset F)
          { pt := s.pt
            ι := { app := fun t => Sigma.desc fun x => s.ι.app x } }
      uniq := fun s m h => by
        apply colimit.hom_ext
        rintro t
        dsimp [liftToFinset]
        apply colimit.hom_ext
        rintro ⟨⟨j, hj⟩⟩
        convert h j using 1
        · simp [← colimit.w (liftToFinset F) ⟨⟨Finset.singleton_subset_iff.2 hj⟩⟩]
          rfl
        · 

Proof state:
case h.e'_3.h
C : Type u
inst✝² : Category.{v, u} C
α : Type w
inst✝¹ : HasFiniteCoproducts C
inst✝ : HasFilteredColimitsOfSize.{w, w, v, u} C
F : Discrete α ⥤ C
s : Cocone F
m :
  { pt := colimit (liftToFinset F),
        ι :=
          Discrete.natTrans fun j =>
            Sigma.ι (fun x => F.obj ↑x) { val := j, property := (_ : j ∈ {j}) } ≫ colimit.ι (liftToFinset F) {j} }.pt ⟶
    s.pt
h :
  ∀ (j : Discrete α),
    { pt := colimit (liftToFinset F),
                ι :=
                  Discrete.natTrans fun j =>
                    Sigma.ι (fun x => F.obj ↑x) { val := j, property := (_ : j ∈ {j}) } ≫
                      colimit.ι (liftToFinset F) {j} }.ι.app
          j ≫
        m =
      s.ι.app j
t : Finset (Discrete α)
j : Discrete α
hj : j ∈ t
e_1✝ : ((Discrete.functor fun x => F.obj ↑x).obj { as := { val := j, property := hj } } ⟶ s.pt) = (F.obj j ⟶ s.pt)
⊢ colimit.ι (Discrete.functor fun x => F.obj ↑x) { as := { val := j, property := hj } } ≫
      colimit.ι
          (Functor.mk
            { obj := fun s => ∐ fun x => F.obj ↑x,
              map := fun {x Y} h =>
                Sigma.desc fun y => Sigma.ι (fun x => F.obj ↑x) { val := ↑y, property := (_ : ↑y ∈ Y) } })
          t ≫
        colimit.desc
          (Functor.mk
            { obj := fun s => ∐ fun x => F.obj ↑x,
              map := fun {x Y} h =>
                Sigma.desc fun y => Sigma.ι (fun x => F.obj ↑x) { val := ↑y, property := (_ : ↑y ∈ Y) } })
          { pt := s.pt, ι := NatTrans.mk fun t => Sigma.desc fun x => s.ι.app ↑x } =
    s.ι.app j

Next tactic:
aesop_cat
theorem hasCoproducts_of_finite_and_filtered [HasFiniteCoproducts C]
    [HasFilteredColimitsOfSize.{w, w} C] : HasCoproducts.{w} C := fun α => by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
α✝ : Type w
inst✝¹ : HasFiniteCoproducts C
inst✝ : HasFilteredColimitsOfSize.{w, w, v, u} C
α : Type w
⊢ HasColimitsOfShape (Discrete α) C

Next tactic:
classical exact ⟨fun F => HasColimit.mk (liftToFinsetColimitCocone F)⟩
theorem hasCoproducts_of_finite_and_filtered [HasFiniteCoproducts C]
    [HasFilteredColimitsOfSize.{w, w} C] : HasCoproducts.{w} C := fun α => by
  classical 

Proof state:
C : Type u
inst✝² : Category.{v, u} C
α✝ : Type w
inst✝¹ : HasFiniteCoproducts C
inst✝ : HasFilteredColimitsOfSize.{w, w, v, u} C
α : Type w
⊢ HasColimitsOfShape (Discrete α) C

Next tactic:
exact ⟨fun F => HasColimit.mk (liftToFinsetColimitCocone F)⟩
instance : Category.{v} (WithTerminal C) where
  Hom X Y := Hom X Y
  id X := id _
  comp := comp
  assoc {a b c d} f g h := by
    -- Porting note: it would be nice to automate this away as well.
    -- I tried splitting this into separate `Quiver` and `Category` instances,
    -- so the `false_of_from_star` destruct rule below can be used here.
    -- That works, but causes mysterious failures of `aesop_cat` in `map`.
    

Proof state:
C : Type u
inst✝ : Category.{v, u} C
a b c d : WithTerminal C
f : a ⟶ b
g : b ⟶ c
h : c ⟶ d
⊢ (f ≫ g) ≫ h = f ≫ g ≫ h

Next tactic:
cases a
instance : Category.{v} (WithTerminal C) where
  Hom X Y := Hom X Y
  id X := id _
  comp := comp
  assoc {a b c d} f g h := by
    -- Porting note: it would be nice to automate this away as well.
    -- I tried splitting this into separate `Quiver` and `Category` instances,
    -- so the `false_of_from_star` destruct rule below can be used here.
    -- That works, but causes mysterious failures of `aesop_cat` in `map`.
    cases a <;> 

Proof state:
case of
C : Type u
inst✝ : Category.{v, u} C
b c d : WithTerminal C
g : b ⟶ c
h : c ⟶ d
a✝ : C
f : of a✝ ⟶ b
⊢ (f ≫ g) ≫ h = f ≫ g ≫ h

Next tactic:
cases b
instance : Category.{v} (WithTerminal C) where
  Hom X Y := Hom X Y
  id X := id _
  comp := comp
  assoc {a b c d} f g h := by
    -- Porting note: it would be nice to automate this away as well.
    -- I tried splitting this into separate `Quiver` and `Category` instances,
    -- so the `false_of_from_star` destruct rule below can be used here.
    -- That works, but causes mysterious failures of `aesop_cat` in `map`.
    cases a <;> 

Proof state:
case star
C : Type u
inst✝ : Category.{v, u} C
b c d : WithTerminal C
g : b ⟶ c
h : c ⟶ d
f : star ⟶ b
⊢ (f ≫ g) ≫ h = f ≫ g ≫ h

Next tactic:
cases b
instance : Category.{v} (WithTerminal C) where
  Hom X Y := Hom X Y
  id X := id _
  comp := comp
  assoc {a b c d} f g h := by
    -- Porting note: it would be nice to automate this away as well.
    -- I tried splitting this into separate `Quiver` and `Category` instances,
    -- so the `false_of_from_star` destruct rule below can be used here.
    -- That works, but causes mysterious failures of `aesop_cat` in `map`.
    cases a <;> cases b <;> 

Proof state:
case of.of
C : Type u
inst✝ : Category.{v, u} C
c d : WithTerminal C
h : c ⟶ d
a✝¹ a✝ : C
g : of a✝ ⟶ c
f : of a✝¹ ⟶ of a✝
⊢ (f ≫ g) ≫ h = f ≫ g ≫ h

Next tactic:
cases c
instance : Category.{v} (WithTerminal C) where
  Hom X Y := Hom X Y
  id X := id _
  comp := comp
  assoc {a b c d} f g h := by
    -- Porting note: it would be nice to automate this away as well.
    -- I tried splitting this into separate `Quiver` and `Category` instances,
    -- so the `false_of_from_star` destruct rule below can be used here.
    -- That works, but causes mysterious failures of `aesop_cat` in `map`.
    cases a <;> cases b <;> 

Proof state:
case of.star
C : Type u
inst✝ : Category.{v, u} C
c d : WithTerminal C
h : c ⟶ d
a✝ : C
g : star ⟶ c
f : of a✝ ⟶ star
⊢ (f ≫ g) ≫ h = f ≫ g ≫ h

Next tactic:
cases c
instance : Category.{v} (WithTerminal C) where
  Hom X Y := Hom X Y
  id X := id _
  comp := comp
  assoc {a b c d} f g h := by
    -- Porting note: it would be nice to automate this away as well.
    -- I tried splitting this into separate `Quiver` and `Category` instances,
    -- so the `false_of_from_star` destruct rule below can be used here.
    -- That works, but causes mysterious failures of `aesop_cat` in `map`.
    cases a <;> cases b <;> 

Proof state:
case star.of
C : Type u
inst✝ : Category.{v, u} C
c d : WithTerminal C
h : c ⟶ d
a✝ : C
g : of a✝ ⟶ c
f : star ⟶ of a✝
⊢ (f ≫ g) ≫ h = f ≫ g ≫ h

Next tactic:
cases c
instance : Category.{v} (WithTerminal C) where
  Hom X Y := Hom X Y
  id X := id _
  comp := comp
  assoc {a b c d} f g h := by
    -- Porting note: it would be nice to automate this away as well.
    -- I tried splitting this into separate `Quiver` and `Category` instances,
    -- so the `false_of_from_star` destruct rule below can be used here.
    -- That works, but causes mysterious failures of `aesop_cat` in `map`.
    cases a <;> cases b <;> 

Proof state:
case star.star
C : Type u
inst✝ : Category.{v, u} C
c d : WithTerminal C
h : c ⟶ d
g : star ⟶ c
f : star ⟶ star
⊢ (f ≫ g) ≫ h = f ≫ g ≫ h

Next tactic:
cases c
instance : Category.{v} (WithTerminal C) where
  Hom X Y := Hom X Y
  id X := id _
  comp := comp
  assoc {a b c d} f g h := by
    -- Porting note: it would be nice to automate this away as well.
    -- I tried splitting this into separate `Quiver` and `Category` instances,
    -- so the `false_of_from_star` destruct rule below can be used here.
    -- That works, but causes mysterious failures of `aesop_cat` in `map`.
    cases a <;> cases b <;> cases c <;> 

Proof state:
case of.of.of
C : Type u
inst✝ : Category.{v, u} C
d : WithTerminal C
a✝² a✝¹ : C
f : of a✝² ⟶ of a✝¹
a✝ : C
h : of a✝ ⟶ d
g : of a✝¹ ⟶ of a✝
⊢ (f ≫ g) ≫ h = f ≫ g ≫ h

Next tactic:
cases d
instance : Category.{v} (WithTerminal C) where
  Hom X Y := Hom X Y
  id X := id _
  comp := comp
  assoc {a b c d} f g h := by
    -- Porting note: it would be nice to automate this away as well.
    -- I tried splitting this into separate `Quiver` and `Category` instances,
    -- so the `false_of_from_star` destruct rule below can be used here.
    -- That works, but causes mysterious failures of `aesop_cat` in `map`.
    cases a <;> cases b <;> cases c <;> 

Proof state:
case of.of.star
C : Type u
inst✝ : Category.{v, u} C
d : WithTerminal C
a✝¹ a✝ : C
f : of a✝¹ ⟶ of a✝
h : star ⟶ d
g : of a✝ ⟶ star
⊢ (f ≫ g) ≫ h = f ≫ g ≫ h

Next tactic:
cases d
instance : Category.{v} (WithTerminal C) where
  Hom X Y := Hom X Y
  id X := id _
  comp := comp
  assoc {a b c d} f g h := by
    -- Porting note: it would be nice to automate this away as well.
    -- I tried splitting this into separate `Quiver` and `Category` instances,
    -- so the `false_of_from_star` destruct rule below can be used here.
    -- That works, but causes mysterious failures of `aesop_cat` in `map`.
    cases a <;> cases b <;> cases c <;> 

Proof state:
case of.star.of
C : Type u
inst✝ : Category.{v, u} C
d : WithTerminal C
a✝¹ : C
f : of a✝¹ ⟶ star
a✝ : C
h : of a✝ ⟶ d
g : star ⟶ of a✝
⊢ (f ≫ g) ≫ h = f ≫ g ≫ h

Next tactic:
cases d
instance : Category.{v} (WithTerminal C) where
  Hom X Y := Hom X Y
  id X := id _
  comp := comp
  assoc {a b c d} f g h := by
    -- Porting note: it would be nice to automate this away as well.
    -- I tried splitting this into separate `Quiver` and `Category` instances,
    -- so the `false_of_from_star` destruct rule below can be used here.
    -- That works, but causes mysterious failures of `aesop_cat` in `map`.
    cases a <;> cases b <;> cases c <;> 

Proof state:
case of.star.star
C : Type u
inst✝ : Category.{v, u} C
d : WithTerminal C
a✝ : C
f : of a✝ ⟶ star
h : star ⟶ d
g : star ⟶ star
⊢ (f ≫ g) ≫ h = f ≫ g ≫ h

Next tactic:
cases d
instance : Category.{v} (WithTerminal C) where
  Hom X Y := Hom X Y
  id X := id _
  comp := comp
  assoc {a b c d} f g h := by
    -- Porting note: it would be nice to automate this away as well.
    -- I tried splitting this into separate `Quiver` and `Category` instances,
    -- so the `false_of_from_star` destruct rule below can be used here.
    -- That works, but causes mysterious failures of `aesop_cat` in `map`.
    cases a <;> cases b <;> cases c <;> 

Proof state:
case star.of.of
C : Type u
inst✝ : Category.{v, u} C
d : WithTerminal C
a✝¹ : C
f : star ⟶ of a✝¹
a✝ : C
h : of a✝ ⟶ d
g : of a✝¹ ⟶ of a✝
⊢ (f ≫ g) ≫ h = f ≫ g ≫ h

Next tactic:
cases d