l3lab/ntp-mathlib huggingface dataset:
@[simp]
theorem pre_map {A₁ A₂ A₃ : C} [Exponentiable A₁] [Exponentiable A₂] [Exponentiable A₃]
    (f : A₁ ⟶ A₂) (g : A₂ ⟶ A₃) : pre (f ≫ g) = pre g ≫ pre f := by
  

Proof state:
C : Type u
inst✝⁵ : Category.{v, u} C
A B X X' Y Y' Z : C
inst✝⁴ : HasFiniteProducts C
inst✝³ : Exponentiable A
A₁ A₂ A₃ : C
inst✝² : Exponentiable A₁
inst✝¹ : Exponentiable A₂
inst✝ : Exponentiable A₃
f : A₁ ⟶ A₂
g : A₂ ⟶ A₃
⊢ pre (f ≫ g) = pre g ≫ pre f

Next tactic:
rw [pre, pre, pre, transferNatTransSelf_comp, prod.functor.map_comp]
/-- If an initial object `I` exists in a CCC, then `A ⨯ I ≅ I`. -/
@[simps]
def zeroMul {I : C} (t : IsInitial I) : A ⨯ I ≅ I where
  hom := Limits.prod.snd
  inv := t.to _
  hom_inv_id := by
    

Proof state:
C : Type u
inst✝² : Category.{v, u} C
A B X X' Y Y' Z : C
inst✝¹ : HasFiniteProducts C
inst✝ : Exponentiable A
I : C
t : IsInitial I
⊢ prod.snd ≫ IsInitial.to t (A ⨯ I) = 𝟙 (A ⨯ I)

Next tactic:
have : (prod.snd : A ⨯ I ⟶ I) = CartesianClosed.uncurry (t.to _) := by
      rw [← curry_eq_iff]
      apply t.hom_ext
/-- If an initial object `I` exists in a CCC, then `A ⨯ I ≅ I`. -/
@[simps]
def zeroMul {I : C} (t : IsInitial I) : A ⨯ I ≅ I where
  hom := Limits.prod.snd
  inv := t.to _
  hom_inv_id := by
    have : (prod.snd : A ⨯ I ⟶ I) = CartesianClosed.uncurry (t.to _) := by
      

Proof state:
C : Type u
inst✝² : Category.{v, u} C
A B X X' Y Y' Z : C
inst✝¹ : HasFiniteProducts C
inst✝ : Exponentiable A
I : C
t : IsInitial I
⊢ prod.snd = CartesianClosed.uncurry (IsInitial.to t (A ⟹ I))

Next tactic:
rw [← curry_eq_iff]
/-- If an initial object `I` exists in a CCC, then `A ⨯ I ≅ I`. -/
@[simps]
def zeroMul {I : C} (t : IsInitial I) : A ⨯ I ≅ I where
  hom := Limits.prod.snd
  inv := t.to _
  hom_inv_id := by
    have : (prod.snd : A ⨯ I ⟶ I) = CartesianClosed.uncurry (t.to _) := by
      rw [← curry_eq_iff]
      

Proof state:
C : Type u
inst✝² : Category.{v, u} C
A B X X' Y Y' Z : C
inst✝¹ : HasFiniteProducts C
inst✝ : Exponentiable A
I : C
t : IsInitial I
⊢ CartesianClosed.curry prod.snd = IsInitial.to t (A ⟹ I)

Next tactic:
apply t.hom_ext
/-- If an initial object `I` exists in a CCC, then `A ⨯ I ≅ I`. -/
@[simps]
def zeroMul {I : C} (t : IsInitial I) : A ⨯ I ≅ I where
  hom := Limits.prod.snd
  inv := t.to _
  hom_inv_id := by
    have : (prod.snd : A ⨯ I ⟶ I) = CartesianClosed.uncurry (t.to _) := by
      rw [← curry_eq_iff]
      apply t.hom_ext
    

Proof state:
C : Type u
inst✝² : Category.{v, u} C
A B X X' Y Y' Z : C
inst✝¹ : HasFiniteProducts C
inst✝ : Exponentiable A
I : C
t : IsInitial I
this : prod.snd = CartesianClosed.uncurry (IsInitial.to t (A ⟹ I))
⊢ prod.snd ≫ IsInitial.to t (A ⨯ I) = 𝟙 (A ⨯ I)

Next tactic:
rw [this, ← uncurry_natural_right, ← eq_curry_iff]
/-- If an initial object `I` exists in a CCC, then `A ⨯ I ≅ I`. -/
@[simps]
def zeroMul {I : C} (t : IsInitial I) : A ⨯ I ≅ I where
  hom := Limits.prod.snd
  inv := t.to _
  hom_inv_id := by
    have : (prod.snd : A ⨯ I ⟶ I) = CartesianClosed.uncurry (t.to _) := by
      rw [← curry_eq_iff]
      apply t.hom_ext
    rw [this, ← uncurry_natural_right, ← eq_curry_iff]
    

Proof state:
C : Type u
inst✝² : Category.{v, u} C
A B X X' Y Y' Z : C
inst✝¹ : HasFiniteProducts C
inst✝ : Exponentiable A
I : C
t : IsInitial I
this : prod.snd = CartesianClosed.uncurry (IsInitial.to t (A ⟹ I))
⊢ IsInitial.to t (A ⟹ I) ≫ (exp A).map (IsInitial.to t (A ⨯ I)) = CartesianClosed.curry (𝟙 (A ⨯ I))

Next tactic:
apply t.hom_ext
/-- If an initial object `0` exists in a CCC then `0^B ≅ 1` for any `B`. -/
def powZero {I : C} (t : IsInitial I) [CartesianClosed C] : I ⟹ B ≅ ⊤_ C where
  hom := default
  inv := CartesianClosed.curry ((mulZero t).hom ≫ t.to _)
  hom_inv_id := by
    -- Porting note: mathport thought that the `mulZero` here was `mul_zero`!
    

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
A B X X' Y Y' Z : C
inst✝² : HasFiniteProducts C
inst✝¹ : Exponentiable A
I : C
t : IsInitial I
inst✝ : CartesianClosed C
⊢ default ≫ CartesianClosed.curry ((mulZero t).hom ≫ IsInitial.to t B) = 𝟙 (I ⟹ B)

Next tactic:
rw [← curry_natural_left, curry_eq_iff, ← cancel_epi (mulZero t).inv]
/-- If an initial object `0` exists in a CCC then `0^B ≅ 1` for any `B`. -/
def powZero {I : C} (t : IsInitial I) [CartesianClosed C] : I ⟹ B ≅ ⊤_ C where
  hom := default
  inv := CartesianClosed.curry ((mulZero t).hom ≫ t.to _)
  hom_inv_id := by
    -- Porting note: mathport thought that the `mulZero` here was `mul_zero`!
    rw [← curry_natural_left, curry_eq_iff, ← cancel_epi (mulZero t).inv]
    

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
A B X X' Y Y' Z : C
inst✝² : HasFiniteProducts C
inst✝¹ : Exponentiable A
I : C
t : IsInitial I
inst✝ : CartesianClosed C
⊢ (mulZero t).inv ≫ prod.map (𝟙 I) default ≫ (mulZero t).hom ≫ IsInitial.to t B =
    (mulZero t).inv ≫ CartesianClosed.uncurry (𝟙 (I ⟹ B))

Next tactic:
apply t.hom_ext
/-- In a CCC with binary coproducts, the distribution morphism is an isomorphism. -/
def prodCoprodDistrib [HasBinaryCoproducts C] [CartesianClosed C] (X Y Z : C) :
    (Z ⨯ X) ⨿ Z ⨯ Y ≅ Z ⨯ X ⨿ Y where
  hom := coprod.desc (Limits.prod.map (𝟙 _) coprod.inl) (Limits.prod.map (𝟙 _) coprod.inr)
  inv :=
    CartesianClosed.uncurry
      (coprod.desc (CartesianClosed.curry coprod.inl) (CartesianClosed.curry coprod.inr))
  hom_inv_id := by
    

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
A B X✝ X' Y✝ Y' Z✝ : C
inst✝³ : HasFiniteProducts C
inst✝² : Exponentiable A
inst✝¹ : HasBinaryCoproducts C
inst✝ : CartesianClosed C
X Y Z : C
⊢ coprod.desc (prod.map (𝟙 Z) coprod.inl) (prod.map (𝟙 Z) coprod.inr) ≫
      CartesianClosed.uncurry (coprod.desc (CartesianClosed.curry coprod.inl) (CartesianClosed.curry coprod.inr)) =
    𝟙 ((Z ⨯ X) ⨿ Z ⨯ Y)

Next tactic:
ext
/-- In a CCC with binary coproducts, the distribution morphism is an isomorphism. -/
def prodCoprodDistrib [HasBinaryCoproducts C] [CartesianClosed C] (X Y Z : C) :
    (Z ⨯ X) ⨿ Z ⨯ Y ≅ Z ⨯ X ⨿ Y where
  hom := coprod.desc (Limits.prod.map (𝟙 _) coprod.inl) (Limits.prod.map (𝟙 _) coprod.inr)
  inv :=
    CartesianClosed.uncurry
      (coprod.desc (CartesianClosed.curry coprod.inl) (CartesianClosed.curry coprod.inr))
  hom_inv_id := by
    ext
    

Proof state:
case h₁
C : Type u
inst✝⁴ : Category.{v, u} C
A B X✝ X' Y✝ Y' Z✝ : C
inst✝³ : HasFiniteProducts C
inst✝² : Exponentiable A
inst✝¹ : HasBinaryCoproducts C
inst✝ : CartesianClosed C
X Y Z : C
⊢ coprod.inl ≫
      coprod.desc (prod.map (𝟙 Z) coprod.inl) (prod.map (𝟙 Z) coprod.inr) ≫
        CartesianClosed.uncurry (coprod.desc (CartesianClosed.curry coprod.inl) (CartesianClosed.curry coprod.inr)) =
    coprod.inl ≫ 𝟙 ((Z ⨯ X) ⨿ Z ⨯ Y)
case h₂
C : Type u
inst✝⁴ : Category.{v, u} C
A B X✝ X' Y✝ Y' Z✝ : C
inst✝³ : HasFiniteProducts C
inst✝² : Exponentiable A
inst✝¹ : HasBinaryCoproducts C
inst✝ : CartesianClosed C
X Y Z : C
⊢ coprod.inr ≫
      coprod.desc (prod.map (𝟙 Z) coprod.inl) (prod.map (𝟙 Z) coprod.inr) ≫
        CartesianClosed.uncurry (coprod.desc (CartesianClosed.curry coprod.inl) (CartesianClosed.curry coprod.inr)) =
    coprod.inr ≫ 𝟙 ((Z ⨯ X) ⨿ Z ⨯ Y)

Next tactic:
rw [coprod.inl_desc_assoc, comp_id, ← uncurry_natural_left, coprod.inl_desc, uncurry_curry]
/-- In a CCC with binary coproducts, the distribution morphism is an isomorphism. -/
def prodCoprodDistrib [HasBinaryCoproducts C] [CartesianClosed C] (X Y Z : C) :
    (Z ⨯ X) ⨿ Z ⨯ Y ≅ Z ⨯ X ⨿ Y where
  hom := coprod.desc (Limits.prod.map (𝟙 _) coprod.inl) (Limits.prod.map (𝟙 _) coprod.inr)
  inv :=
    CartesianClosed.uncurry
      (coprod.desc (CartesianClosed.curry coprod.inl) (CartesianClosed.curry coprod.inr))
  hom_inv_id := by
    ext
    rw [coprod.inl_desc_assoc, comp_id, ← uncurry_natural_left, coprod.inl_desc, uncurry_curry]
    

Proof state:
case h₂
C : Type u
inst✝⁴ : Category.{v, u} C
A B X✝ X' Y✝ Y' Z✝ : C
inst✝³ : HasFiniteProducts C
inst✝² : Exponentiable A
inst✝¹ : HasBinaryCoproducts C
inst✝ : CartesianClosed C
X Y Z : C
⊢ coprod.inr ≫
      coprod.desc (prod.map (𝟙 Z) coprod.inl) (prod.map (𝟙 Z) coprod.inr) ≫
        CartesianClosed.uncurry (coprod.desc (CartesianClosed.curry coprod.inl) (CartesianClosed.curry coprod.inr)) =
    coprod.inr ≫ 𝟙 ((Z ⨯ X) ⨿ Z ⨯ Y)

Next tactic:
rw [coprod.inr_desc_assoc, comp_id, ← uncurry_natural_left, coprod.inr_desc, uncurry_curry]
/-- In a CCC with binary coproducts, the distribution morphism is an isomorphism. -/
def prodCoprodDistrib [HasBinaryCoproducts C] [CartesianClosed C] (X Y Z : C) :
    (Z ⨯ X) ⨿ Z ⨯ Y ≅ Z ⨯ X ⨿ Y where
  hom := coprod.desc (Limits.prod.map (𝟙 _) coprod.inl) (Limits.prod.map (𝟙 _) coprod.inr)
  inv :=
    CartesianClosed.uncurry
      (coprod.desc (CartesianClosed.curry coprod.inl) (CartesianClosed.curry coprod.inr))
  hom_inv_id := by
    ext
    rw [coprod.inl_desc_assoc, comp_id, ← uncurry_natural_left, coprod.inl_desc, uncurry_curry]
    rw [coprod.inr_desc_assoc, comp_id, ← uncurry_natural_left, coprod.inr_desc, uncurry_curry]
  inv_hom_id := by
    

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
A B X✝ X' Y✝ Y' Z✝ : C
inst✝³ : HasFiniteProducts C
inst✝² : Exponentiable A
inst✝¹ : HasBinaryCoproducts C
inst✝ : CartesianClosed C
X Y Z : C
⊢ CartesianClosed.uncurry (coprod.desc (CartesianClosed.curry coprod.inl) (CartesianClosed.curry coprod.inr)) ≫
      coprod.desc (prod.map (𝟙 Z) coprod.inl) (prod.map (𝟙 Z) coprod.inr) =
    𝟙 (Z ⨯ X ⨿ Y)

Next tactic:
rw [← uncurry_natural_right, ← eq_curry_iff]
/-- In a CCC with binary coproducts, the distribution morphism is an isomorphism. -/
def prodCoprodDistrib [HasBinaryCoproducts C] [CartesianClosed C] (X Y Z : C) :
    (Z ⨯ X) ⨿ Z ⨯ Y ≅ Z ⨯ X ⨿ Y where
  hom := coprod.desc (Limits.prod.map (𝟙 _) coprod.inl) (Limits.prod.map (𝟙 _) coprod.inr)
  inv :=
    CartesianClosed.uncurry
      (coprod.desc (CartesianClosed.curry coprod.inl) (CartesianClosed.curry coprod.inr))
  hom_inv_id := by
    ext
    rw [coprod.inl_desc_assoc, comp_id, ← uncurry_natural_left, coprod.inl_desc, uncurry_curry]
    rw [coprod.inr_desc_assoc, comp_id, ← uncurry_natural_left, coprod.inr_desc, uncurry_curry]
  inv_hom_id := by
    rw [← uncurry_natural_right, ← eq_curry_iff]
    

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
A B X✝ X' Y✝ Y' Z✝ : C
inst✝³ : HasFiniteProducts C
inst✝² : Exponentiable A
inst✝¹ : HasBinaryCoproducts C
inst✝ : CartesianClosed C
X Y Z : C
⊢ coprod.desc (CartesianClosed.curry coprod.inl) (CartesianClosed.curry coprod.inr) ≫
      (exp Z).map (coprod.desc (prod.map (𝟙 Z) coprod.inl) (prod.map (𝟙 Z) coprod.inr)) =
    CartesianClosed.curry (𝟙 (Z ⨯ X ⨿ Y))

Next tactic:
ext
/-- In a CCC with binary coproducts, the distribution morphism is an isomorphism. -/
def prodCoprodDistrib [HasBinaryCoproducts C] [CartesianClosed C] (X Y Z : C) :
    (Z ⨯ X) ⨿ Z ⨯ Y ≅ Z ⨯ X ⨿ Y where
  hom := coprod.desc (Limits.prod.map (𝟙 _) coprod.inl) (Limits.prod.map (𝟙 _) coprod.inr)
  inv :=
    CartesianClosed.uncurry
      (coprod.desc (CartesianClosed.curry coprod.inl) (CartesianClosed.curry coprod.inr))
  hom_inv_id := by
    ext
    rw [coprod.inl_desc_assoc, comp_id, ← uncurry_natural_left, coprod.inl_desc, uncurry_curry]
    rw [coprod.inr_desc_assoc, comp_id, ← uncurry_natural_left, coprod.inr_desc, uncurry_curry]
  inv_hom_id := by
    rw [← uncurry_natural_right, ← eq_curry_iff]
    ext
    

Proof state:
case h₁
C : Type u
inst✝⁴ : Category.{v, u} C
A B X✝ X' Y✝ Y' Z✝ : C
inst✝³ : HasFiniteProducts C
inst✝² : Exponentiable A
inst✝¹ : HasBinaryCoproducts C
inst✝ : CartesianClosed C
X Y Z : C
⊢ coprod.inl ≫
      coprod.desc (CartesianClosed.curry coprod.inl) (CartesianClosed.curry coprod.inr) ≫
        (exp Z).map (coprod.desc (prod.map (𝟙 Z) coprod.inl) (prod.map (𝟙 Z) coprod.inr)) =
    coprod.inl ≫ CartesianClosed.curry (𝟙 (Z ⨯ X ⨿ Y))
case h₂
C : Type u
inst✝⁴ : Category.{v, u} C
A B X✝ X' Y✝ Y' Z✝ : C
inst✝³ : HasFiniteProducts C
inst✝² : Exponentiable A
inst✝¹ : HasBinaryCoproducts C
inst✝ : CartesianClosed C
X Y Z : C
⊢ coprod.inr ≫
      coprod.desc (CartesianClosed.curry coprod.inl) (CartesianClosed.curry coprod.inr) ≫
        (exp Z).map (coprod.desc (prod.map (𝟙 Z) coprod.inl) (prod.map (𝟙 Z) coprod.inr)) =
    coprod.inr ≫ CartesianClosed.curry (𝟙 (Z ⨯ X ⨿ Y))

Next tactic:
rw [coprod.inl_desc_assoc, ← curry_natural_right, coprod.inl_desc, ← curry_natural_left,
      comp_id]
/-- In a CCC with binary coproducts, the distribution morphism is an isomorphism. -/
def prodCoprodDistrib [HasBinaryCoproducts C] [CartesianClosed C] (X Y Z : C) :
    (Z ⨯ X) ⨿ Z ⨯ Y ≅ Z ⨯ X ⨿ Y where
  hom := coprod.desc (Limits.prod.map (𝟙 _) coprod.inl) (Limits.prod.map (𝟙 _) coprod.inr)
  inv :=
    CartesianClosed.uncurry
      (coprod.desc (CartesianClosed.curry coprod.inl) (CartesianClosed.curry coprod.inr))
  hom_inv_id := by
    ext
    rw [coprod.inl_desc_assoc, comp_id, ← uncurry_natural_left, coprod.inl_desc, uncurry_curry]
    rw [coprod.inr_desc_assoc, comp_id, ← uncurry_natural_left, coprod.inr_desc, uncurry_curry]
  inv_hom_id := by
    rw [← uncurry_natural_right, ← eq_curry_iff]
    ext
    rw [coprod.inl_desc_assoc, ← curry_natural_right, coprod.inl_desc, ← curry_natural_left,
      comp_id]
    

Proof state:
case h₂
C : Type u
inst✝⁴ : Category.{v, u} C
A B X✝ X' Y✝ Y' Z✝ : C
inst✝³ : HasFiniteProducts C
inst✝² : Exponentiable A
inst✝¹ : HasBinaryCoproducts C
inst✝ : CartesianClosed C
X Y Z : C
⊢ coprod.inr ≫
      coprod.desc (CartesianClosed.curry coprod.inl) (CartesianClosed.curry coprod.inr) ≫
        (exp Z).map (coprod.desc (prod.map (𝟙 Z) coprod.inl) (prod.map (𝟙 Z) coprod.inr)) =
    coprod.inr ≫ CartesianClosed.curry (𝟙 (Z ⨯ X ⨿ Y))

Next tactic:
rw [coprod.inr_desc_assoc, ← curry_natural_right, coprod.inr_desc, ← curry_natural_left,
      comp_id]
/-- If an initial object `I` exists in a CCC then it is a strict initial object,
i.e. any morphism to `I` is an iso.
This actually shows a slightly stronger version: any morphism to an initial object from an
exponentiable object is an isomorphism.
-/
theorem strict_initial {I : C} (t : IsInitial I) (f : A ⟶ I) : IsIso f := by
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
A B X X' Y Y' Z : C
inst✝¹ : HasFiniteProducts C
inst✝ : Exponentiable A
I : C
t : IsInitial I
f : A ⟶ I
⊢ IsIso f

Next tactic:
haveI : Mono (prod.lift (𝟙 A) f ≫ (zeroMul t).hom) := mono_comp _ _
/-- If an initial object `I` exists in a CCC then it is a strict initial object,
i.e. any morphism to `I` is an iso.
This actually shows a slightly stronger version: any morphism to an initial object from an
exponentiable object is an isomorphism.
-/
theorem strict_initial {I : C} (t : IsInitial I) (f : A ⟶ I) : IsIso f := by
  haveI : Mono (prod.lift (𝟙 A) f ≫ (zeroMul t).hom) := mono_comp _ _
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
A B X X' Y Y' Z : C
inst✝¹ : HasFiniteProducts C
inst✝ : Exponentiable A
I : C
t : IsInitial I
f : A ⟶ I
this : Mono (prod.lift (𝟙 A) f ≫ (zeroMul t).hom)
⊢ IsIso f

Next tactic:
rw [zeroMul_hom, prod.lift_snd] at this
/-- If an initial object `I` exists in a CCC then it is a strict initial object,
i.e. any morphism to `I` is an iso.
This actually shows a slightly stronger version: any morphism to an initial object from an
exponentiable object is an isomorphism.
-/
theorem strict_initial {I : C} (t : IsInitial I) (f : A ⟶ I) : IsIso f := by
  haveI : Mono (prod.lift (𝟙 A) f ≫ (zeroMul t).hom) := mono_comp _ _
  rw [zeroMul_hom, prod.lift_snd] at this
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
A B X X' Y Y' Z : C
inst✝¹ : HasFiniteProducts C
inst✝ : Exponentiable A
I : C
t : IsInitial I
f : A ⟶ I
this : Mono f
⊢ IsIso f

Next tactic:
haveI : IsSplitEpi f := IsSplitEpi.mk' ⟨t.to _, t.hom_ext _ _⟩
/-- If an initial object `I` exists in a CCC then it is a strict initial object,
i.e. any morphism to `I` is an iso.
This actually shows a slightly stronger version: any morphism to an initial object from an
exponentiable object is an isomorphism.
-/
theorem strict_initial {I : C} (t : IsInitial I) (f : A ⟶ I) : IsIso f := by
  haveI : Mono (prod.lift (𝟙 A) f ≫ (zeroMul t).hom) := mono_comp _ _
  rw [zeroMul_hom, prod.lift_snd] at this
  haveI : IsSplitEpi f := IsSplitEpi.mk' ⟨t.to _, t.hom_ext _ _⟩
  

Proof state:
C : Type u
inst✝² : Category.{v, u} C
A B X X' Y Y' Z : C
inst✝¹ : HasFiniteProducts C
inst✝ : Exponentiable A
I : C
t : IsInitial I
f : A ⟶ I
this✝ : Mono f
this : IsSplitEpi f
⊢ IsIso f

Next tactic:
apply isIso_of_mono_of_isSplitEpi
/-- If an initial object `0` exists in a CCC then every morphism from it is monic. -/
theorem initial_mono {I : C} (B : C) (t : IsInitial I) [CartesianClosed C] : Mono (t.to B) :=
  ⟨fun g h _ => by
    

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
A B✝ X X' Y Y' Z : C
inst✝² : HasFiniteProducts C
inst✝¹ : Exponentiable A
I B : C
t : IsInitial I
inst✝ : CartesianClosed C
Z✝ : C
g h : Z✝ ⟶ I
x✝ : g ≫ IsInitial.to t B = h ≫ IsInitial.to t B
⊢ g = h

Next tactic:
haveI := strict_initial t g
/-- If an initial object `0` exists in a CCC then every morphism from it is monic. -/
theorem initial_mono {I : C} (B : C) (t : IsInitial I) [CartesianClosed C] : Mono (t.to B) :=
  ⟨fun g h _ => by
    haveI := strict_initial t g
    

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
A B✝ X X' Y Y' Z : C
inst✝² : HasFiniteProducts C
inst✝¹ : Exponentiable A
I B : C
t : IsInitial I
inst✝ : CartesianClosed C
Z✝ : C
g h : Z✝ ⟶ I
x✝ : g ≫ IsInitial.to t B = h ≫ IsInitial.to t B
this : IsIso g
⊢ g = h

Next tactic:
haveI := strict_initial t h
/-- If an initial object `0` exists in a CCC then every morphism from it is monic. -/
theorem initial_mono {I : C} (B : C) (t : IsInitial I) [CartesianClosed C] : Mono (t.to B) :=
  ⟨fun g h _ => by
    haveI := strict_initial t g
    haveI := strict_initial t h
    

Proof state:
C : Type u
inst✝³ : Category.{v, u} C
A B✝ X X' Y Y' Z : C
inst✝² : HasFiniteProducts C
inst✝¹ : Exponentiable A
I B : C
t : IsInitial I
inst✝ : CartesianClosed C
Z✝ : C
g h : Z✝ ⟶ I
x✝ : g ≫ IsInitial.to t B = h ≫ IsInitial.to t B
this✝ : IsIso g
this : IsIso h
⊢ g = h

Next tactic:
exact eq_of_inv_eq_inv (t.hom_ext _ _)
/-- Transport the property of being cartesian closed across an equivalence of categories.

Note we didn't require any coherence between the choice of finite products here, since we transport
along the `prodComparison` isomorphism.
-/
def cartesianClosedOfEquiv (e : C ≌ D) [h : CartesianClosed C] : CartesianClosed D where
  closed X :=
    { isAdj := by
        

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
A B X✝ X' Y Y' Z : C
inst✝³ : HasFiniteProducts C
inst✝² : Exponentiable A
D : Type u₂
inst✝¹ : Category.{v, u₂} D
inst✝ : HasFiniteProducts D
e : C ≌ D
h : CartesianClosed C
X : D
⊢ IsLeftAdjoint (MonoidalCategory.tensorLeft X)

Next tactic:
haveI q : Exponentiable (e.inverse.obj X) := inferInstance
/-- Transport the property of being cartesian closed across an equivalence of categories.

Note we didn't require any coherence between the choice of finite products here, since we transport
along the `prodComparison` isomorphism.
-/
def cartesianClosedOfEquiv (e : C ≌ D) [h : CartesianClosed C] : CartesianClosed D where
  closed X :=
    { isAdj := by
        haveI q : Exponentiable (e.inverse.obj X) := inferInstance
        

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
A B X✝ X' Y Y' Z : C
inst✝³ : HasFiniteProducts C
inst✝² : Exponentiable A
D : Type u₂
inst✝¹ : Category.{v, u₂} D
inst✝ : HasFiniteProducts D
e : C ≌ D
h : CartesianClosed C
X : D
q : Exponentiable (e.inverse.obj X)
⊢ IsLeftAdjoint (MonoidalCategory.tensorLeft X)

Next tactic:
have : IsLeftAdjoint (prod.functor.obj (e.inverse.obj X)) := q.isAdj
/-- Transport the property of being cartesian closed across an equivalence of categories.

Note we didn't require any coherence between the choice of finite products here, since we transport
along the `prodComparison` isomorphism.
-/
def cartesianClosedOfEquiv (e : C ≌ D) [h : CartesianClosed C] : CartesianClosed D where
  closed X :=
    { isAdj := by
        haveI q : Exponentiable (e.inverse.obj X) := inferInstance
        have : IsLeftAdjoint (prod.functor.obj (e.inverse.obj X)) := q.isAdj
        

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
A B X✝ X' Y Y' Z : C
inst✝³ : HasFiniteProducts C
inst✝² : Exponentiable A
D : Type u₂
inst✝¹ : Category.{v, u₂} D
inst✝ : HasFiniteProducts D
e : C ≌ D
h : CartesianClosed C
X : D
q : Exponentiable (e.inverse.obj X)
this : IsLeftAdjoint (prod.functor.obj (e.inverse.obj X))
⊢ IsLeftAdjoint (MonoidalCategory.tensorLeft X)

Next tactic:
have : e.functor ⋙ prod.functor.obj X ⋙ e.inverse ≅
            prod.functor.obj (e.inverse.obj X) := by
          apply NatIso.ofComponents _ _
          · intro Y
            apply asIso (prodComparison e.inverse X (e.functor.obj Y)) ≪≫ _
            apply prod.mapIso (Iso.refl _) (e.unitIso.app Y).symm
          · intro Y Z g
            dsimp
            simp [prodComparison, prod.comp_lift, ← e.inverse.map_comp, ← e.inverse.map_comp_assoc]
/-- Transport the property of being cartesian closed across an equivalence of categories.

Note we didn't require any coherence between the choice of finite products here, since we transport
along the `prodComparison` isomorphism.
-/
def cartesianClosedOfEquiv (e : C ≌ D) [h : CartesianClosed C] : CartesianClosed D where
  closed X :=
    { isAdj := by
        haveI q : Exponentiable (e.inverse.obj X) := inferInstance
        have : IsLeftAdjoint (prod.functor.obj (e.inverse.obj X)) := q.isAdj
        have : e.functor ⋙ prod.functor.obj X ⋙ e.inverse ≅
            prod.functor.obj (e.inverse.obj X) := by
          

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
A B X✝ X' Y Y' Z : C
inst✝³ : HasFiniteProducts C
inst✝² : Exponentiable A
D : Type u₂
inst✝¹ : Category.{v, u₂} D
inst✝ : HasFiniteProducts D
e : C ≌ D
h : CartesianClosed C
X : D
q : Exponentiable (e.inverse.obj X)
this : IsLeftAdjoint (prod.functor.obj (e.inverse.obj X))
⊢ e.functor ⋙ prod.functor.obj X ⋙ e.inverse ≅ prod.functor.obj (e.inverse.obj X)

Next tactic:
apply NatIso.ofComponents _ _
/-- Transport the property of being cartesian closed across an equivalence of categories.

Note we didn't require any coherence between the choice of finite products here, since we transport
along the `prodComparison` isomorphism.
-/
def cartesianClosedOfEquiv (e : C ≌ D) [h : CartesianClosed C] : CartesianClosed D where
  closed X :=
    { isAdj := by
        haveI q : Exponentiable (e.inverse.obj X) := inferInstance
        have : IsLeftAdjoint (prod.functor.obj (e.inverse.obj X)) := q.isAdj
        have : e.functor ⋙ prod.functor.obj X ⋙ e.inverse ≅
            prod.functor.obj (e.inverse.obj X) := by
          apply NatIso.ofComponents _ _
          · 

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
A B X✝ X' Y Y' Z : C
inst✝³ : HasFiniteProducts C
inst✝² : Exponentiable A
D : Type u₂
inst✝¹ : Category.{v, u₂} D
inst✝ : HasFiniteProducts D
e : C ≌ D
h : CartesianClosed C
X : D
q : Exponentiable (e.inverse.obj X)
this : IsLeftAdjoint (prod.functor.obj (e.inverse.obj X))
⊢ (X_1 : C) → (e.functor ⋙ prod.functor.obj X ⋙ e.inverse).obj X_1 ≅ (prod.functor.obj (e.inverse.obj X)).obj X_1

Next tactic:
intro Y
/-- Transport the property of being cartesian closed across an equivalence of categories.

Note we didn't require any coherence between the choice of finite products here, since we transport
along the `prodComparison` isomorphism.
-/
def cartesianClosedOfEquiv (e : C ≌ D) [h : CartesianClosed C] : CartesianClosed D where
  closed X :=
    { isAdj := by
        haveI q : Exponentiable (e.inverse.obj X) := inferInstance
        have : IsLeftAdjoint (prod.functor.obj (e.inverse.obj X)) := q.isAdj
        have : e.functor ⋙ prod.functor.obj X ⋙ e.inverse ≅
            prod.functor.obj (e.inverse.obj X) := by
          apply NatIso.ofComponents _ _
          · intro Y
            

Proof state:
C : Type u
inst✝⁴ : Category.{v, u} C
A B X✝ X' Y✝ Y' Z : C
inst✝³ : HasFiniteProducts C
inst✝² : Exponentiable A
D : Type u₂
inst✝¹ : Category.{v, u₂} D
inst✝ : HasFiniteProducts D
e : C ≌ D
h : CartesianClosed C
X : D
q : Exponentiable (e.inverse.obj X)
this : IsLeftAdjoint (prod.functor.obj (e.inverse.obj X))
Y : C
⊢ (e.functor ⋙ prod.functor.obj X ⋙ e.inverse).obj Y ≅ (prod.functor.obj (e.inverse.obj X)).obj Y

Next tactic:
apply asIso (prodComparison e.inverse X (e.functor.obj Y)) ≪≫ _