l3lab/ntp-mathlib huggingface dataset:
/-- `AddSubmonoid.neg` distributes over multiplication.

This is available as an instance in the `Pointwise` locale. -/
protected def hasDistribNeg : HasDistribNeg (AddSubmonoid R) :=
  { AddSubmonoid.involutiveNeg with
    neg_mul := fun x y => by
      refine'
          le_antisymm (mul_le.2 fun m hm n hn => _)
            ((AddSubmonoid.neg_le _ _).2 <| mul_le.2 fun m hm n hn => _) <;>
        

Proof state:
case refine'_1
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocRing R
src✝ : InvolutiveNeg (AddSubmonoid R) := involutiveNeg
x y : AddSubmonoid R
m : R
hm : m ∈ -x
n : R
hn : n ∈ y
⊢ m * n ∈ -(x * y)

Next tactic:
simp only [AddSubmonoid.mem_neg, ← neg_mul] at *
/-- `AddSubmonoid.neg` distributes over multiplication.

This is available as an instance in the `Pointwise` locale. -/
protected def hasDistribNeg : HasDistribNeg (AddSubmonoid R) :=
  { AddSubmonoid.involutiveNeg with
    neg_mul := fun x y => by
      refine'
          le_antisymm (mul_le.2 fun m hm n hn => _)
            ((AddSubmonoid.neg_le _ _).2 <| mul_le.2 fun m hm n hn => _) <;>
        

Proof state:
case refine'_2
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocRing R
src✝ : InvolutiveNeg (AddSubmonoid R) := involutiveNeg
x y : AddSubmonoid R
m : R
hm : m ∈ x
n : R
hn : n ∈ y
⊢ m * n ∈ -(-x * y)

Next tactic:
simp only [AddSubmonoid.mem_neg, ← neg_mul] at *
/-- `AddSubmonoid.neg` distributes over multiplication.

This is available as an instance in the `Pointwise` locale. -/
protected def hasDistribNeg : HasDistribNeg (AddSubmonoid R) :=
  { AddSubmonoid.involutiveNeg with
    neg_mul := fun x y => by
      refine'
          le_antisymm (mul_le.2 fun m hm n hn => _)
            ((AddSubmonoid.neg_le _ _).2 <| mul_le.2 fun m hm n hn => _) <;>
        simp only [AddSubmonoid.mem_neg, ← neg_mul] at *
      · 

Proof state:
case refine'_1
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocRing R
src✝ : InvolutiveNeg (AddSubmonoid R) := involutiveNeg
x y : AddSubmonoid R
m n : R
hn : n ∈ y
hm : -m ∈ x
⊢ -m * n ∈ x * y

Next tactic:
exact mul_mem_mul hm hn
/-- `AddSubmonoid.neg` distributes over multiplication.

This is available as an instance in the `Pointwise` locale. -/
protected def hasDistribNeg : HasDistribNeg (AddSubmonoid R) :=
  { AddSubmonoid.involutiveNeg with
    neg_mul := fun x y => by
      refine'
          le_antisymm (mul_le.2 fun m hm n hn => _)
            ((AddSubmonoid.neg_le _ _).2 <| mul_le.2 fun m hm n hn => _) <;>
        simp only [AddSubmonoid.mem_neg, ← neg_mul] at *
      · exact mul_mem_mul hm hn
      · 

Proof state:
case refine'_2
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocRing R
src✝ : InvolutiveNeg (AddSubmonoid R) := involutiveNeg
x y : AddSubmonoid R
m : R
hm : m ∈ x
n : R
hn : n ∈ y
⊢ -m * n ∈ -x * y

Next tactic:
exact mul_mem_mul (neg_mem_neg.2 hm) hn
/-- `AddSubmonoid.neg` distributes over multiplication.

This is available as an instance in the `Pointwise` locale. -/
protected def hasDistribNeg : HasDistribNeg (AddSubmonoid R) :=
  { AddSubmonoid.involutiveNeg with
    neg_mul := fun x y => by
      refine'
          le_antisymm (mul_le.2 fun m hm n hn => _)
            ((AddSubmonoid.neg_le _ _).2 <| mul_le.2 fun m hm n hn => _) <;>
        simp only [AddSubmonoid.mem_neg, ← neg_mul] at *
      · exact mul_mem_mul hm hn
      · exact mul_mem_mul (neg_mem_neg.2 hm) hn
    mul_neg := fun x y => by
      

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocRing R
src✝ : InvolutiveNeg (AddSubmonoid R) := involutiveNeg
x y : AddSubmonoid R
⊢ x * -y = -(x * y)

Next tactic:
refine'
          le_antisymm (mul_le.2 fun m hm n hn => _)
            ((AddSubmonoid.neg_le _ _).2 <| mul_le.2 fun m hm n hn => _)
/-- `AddSubmonoid.neg` distributes over multiplication.

This is available as an instance in the `Pointwise` locale. -/
protected def hasDistribNeg : HasDistribNeg (AddSubmonoid R) :=
  { AddSubmonoid.involutiveNeg with
    neg_mul := fun x y => by
      refine'
          le_antisymm (mul_le.2 fun m hm n hn => _)
            ((AddSubmonoid.neg_le _ _).2 <| mul_le.2 fun m hm n hn => _) <;>
        simp only [AddSubmonoid.mem_neg, ← neg_mul] at *
      · exact mul_mem_mul hm hn
      · exact mul_mem_mul (neg_mem_neg.2 hm) hn
    mul_neg := fun x y => by
      refine'
          le_antisymm (mul_le.2 fun m hm n hn => _)
            ((AddSubmonoid.neg_le _ _).2 <| mul_le.2 fun m hm n hn => _) <;>
        

Proof state:
case refine'_1
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocRing R
src✝ : InvolutiveNeg (AddSubmonoid R) := involutiveNeg
x y : AddSubmonoid R
m : R
hm : m ∈ x
n : R
hn : n ∈ -y
⊢ m * n ∈ -(x * y)

Next tactic:
simp only [AddSubmonoid.mem_neg, ← mul_neg] at *
/-- `AddSubmonoid.neg` distributes over multiplication.

This is available as an instance in the `Pointwise` locale. -/
protected def hasDistribNeg : HasDistribNeg (AddSubmonoid R) :=
  { AddSubmonoid.involutiveNeg with
    neg_mul := fun x y => by
      refine'
          le_antisymm (mul_le.2 fun m hm n hn => _)
            ((AddSubmonoid.neg_le _ _).2 <| mul_le.2 fun m hm n hn => _) <;>
        simp only [AddSubmonoid.mem_neg, ← neg_mul] at *
      · exact mul_mem_mul hm hn
      · exact mul_mem_mul (neg_mem_neg.2 hm) hn
    mul_neg := fun x y => by
      refine'
          le_antisymm (mul_le.2 fun m hm n hn => _)
            ((AddSubmonoid.neg_le _ _).2 <| mul_le.2 fun m hm n hn => _) <;>
        

Proof state:
case refine'_2
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocRing R
src✝ : InvolutiveNeg (AddSubmonoid R) := involutiveNeg
x y : AddSubmonoid R
m : R
hm : m ∈ x
n : R
hn : n ∈ y
⊢ m * n ∈ -(x * -y)

Next tactic:
simp only [AddSubmonoid.mem_neg, ← mul_neg] at *
/-- `AddSubmonoid.neg` distributes over multiplication.

This is available as an instance in the `Pointwise` locale. -/
protected def hasDistribNeg : HasDistribNeg (AddSubmonoid R) :=
  { AddSubmonoid.involutiveNeg with
    neg_mul := fun x y => by
      refine'
          le_antisymm (mul_le.2 fun m hm n hn => _)
            ((AddSubmonoid.neg_le _ _).2 <| mul_le.2 fun m hm n hn => _) <;>
        simp only [AddSubmonoid.mem_neg, ← neg_mul] at *
      · exact mul_mem_mul hm hn
      · exact mul_mem_mul (neg_mem_neg.2 hm) hn
    mul_neg := fun x y => by
      refine'
          le_antisymm (mul_le.2 fun m hm n hn => _)
            ((AddSubmonoid.neg_le _ _).2 <| mul_le.2 fun m hm n hn => _) <;>
        simp only [AddSubmonoid.mem_neg, ← mul_neg] at *
      · 

Proof state:
case refine'_1
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocRing R
src✝ : InvolutiveNeg (AddSubmonoid R) := involutiveNeg
x y : AddSubmonoid R
m : R
hm : m ∈ x
n : R
hn : -n ∈ y
⊢ m * -n ∈ x * y

Next tactic:
exact mul_mem_mul hm hn
/-- `AddSubmonoid.neg` distributes over multiplication.

This is available as an instance in the `Pointwise` locale. -/
protected def hasDistribNeg : HasDistribNeg (AddSubmonoid R) :=
  { AddSubmonoid.involutiveNeg with
    neg_mul := fun x y => by
      refine'
          le_antisymm (mul_le.2 fun m hm n hn => _)
            ((AddSubmonoid.neg_le _ _).2 <| mul_le.2 fun m hm n hn => _) <;>
        simp only [AddSubmonoid.mem_neg, ← neg_mul] at *
      · exact mul_mem_mul hm hn
      · exact mul_mem_mul (neg_mem_neg.2 hm) hn
    mul_neg := fun x y => by
      refine'
          le_antisymm (mul_le.2 fun m hm n hn => _)
            ((AddSubmonoid.neg_le _ _).2 <| mul_le.2 fun m hm n hn => _) <;>
        simp only [AddSubmonoid.mem_neg, ← mul_neg] at *
      · exact mul_mem_mul hm hn
      · 

Proof state:
case refine'_2
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : NonUnitalNonAssocRing R
src✝ : InvolutiveNeg (AddSubmonoid R) := involutiveNeg
x y : AddSubmonoid R
m : R
hm : m ∈ x
n : R
hn : n ∈ y
⊢ m * -n ∈ x * -y

Next tactic:
exact mul_mem_mul hm (neg_mem_neg.2 hn)
/-- A `MulOneClass` structure on additive submonoids of a (possibly, non-associative) semiring. -/
protected def mulOneClass : MulOneClass (AddSubmonoid R) where
  one := 1
  mul := (· * ·)
  one_mul M := by 

Proof state:
α : Type u_1
G : Type u_2
M✝ : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M✝
inst✝¹ : AddMonoid A
inst✝ : NonAssocSemiring R
M : AddSubmonoid R
⊢ 1 * M = M

Next tactic:
rw [one_eq_closure_one_set, ← closure_eq M, closure_mul_closure, one_mul]
/-- A `MulOneClass` structure on additive submonoids of a (possibly, non-associative) semiring. -/
protected def mulOneClass : MulOneClass (AddSubmonoid R) where
  one := 1
  mul := (· * ·)
  one_mul M := by rw [one_eq_closure_one_set, ← closure_eq M, closure_mul_closure, one_mul]
  mul_one M := by 

Proof state:
α : Type u_1
G : Type u_2
M✝ : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M✝
inst✝¹ : AddMonoid A
inst✝ : NonAssocSemiring R
M : AddSubmonoid R
⊢ M * 1 = M

Next tactic:
rw [one_eq_closure_one_set, ← closure_eq M, closure_mul_closure, mul_one]
theorem closure_pow (s : Set R) : ∀ n : ℕ, closure s ^ n = closure (s ^ n)
  | 0 => by 

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : Semiring R
s : Set R
⊢ closure s ^ 0 = closure (s ^ 0)

Next tactic:
rw [pow_zero, pow_zero, one_eq_closure_one_set]
theorem closure_pow (s : Set R) : ∀ n : ℕ, closure s ^ n = closure (s ^ n)
  | 0 => by rw [pow_zero, pow_zero, one_eq_closure_one_set]
  | n + 1 => by 

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : Semiring R
s : Set R
n : ℕ
⊢ closure s ^ (n + 1) = closure (s ^ (n + 1))

Next tactic:
rw [pow_succ, pow_succ, closure_pow s n, closure_mul_closure]
theorem pow_eq_closure_pow_set (s : AddSubmonoid R) (n : ℕ) :
    s ^ n = closure ((s : Set R) ^ n) := by
  

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : Semiring R
s : AddSubmonoid R
n : ℕ
⊢ s ^ n = closure (↑s ^ n)

Next tactic:
rw [← closure_pow, closure_eq]
@[to_additive]
theorem submonoid_closure (hpos : ∀ x : α, x ∈ s → 1 ≤ x) (h : s.IsPwo) :
    IsPwo (Submonoid.closure s : Set α) := by
  

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : OrderedCancelCommMonoid α
s : Set α
hpos : ∀ x ∈ s, 1 ≤ x
h : IsPwo s
⊢ IsPwo ↑(Submonoid.closure s)

Next tactic:
rw [Submonoid.closure_eq_image_prod]
@[to_additive]
theorem submonoid_closure (hpos : ∀ x : α, x ∈ s → 1 ≤ x) (h : s.IsPwo) :
    IsPwo (Submonoid.closure s : Set α) := by
  rw [Submonoid.closure_eq_image_prod]
  

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : OrderedCancelCommMonoid α
s : Set α
hpos : ∀ x ∈ s, 1 ≤ x
h : IsPwo s
⊢ IsPwo (List.prod '' {l | ∀ x ∈ l, x ∈ s})

Next tactic:
refine' (h.partiallyWellOrderedOn_sublistForall₂ (· ≤ ·)).image_of_monotone_on _
@[to_additive]
theorem submonoid_closure (hpos : ∀ x : α, x ∈ s → 1 ≤ x) (h : s.IsPwo) :
    IsPwo (Submonoid.closure s : Set α) := by
  rw [Submonoid.closure_eq_image_prod]
  refine' (h.partiallyWellOrderedOn_sublistForall₂ (· ≤ ·)).image_of_monotone_on _
  

Proof state:
α : Type u_1
G : Type u_2
M : Type u_3
R : Type u_4
A : Type u_5
inst✝² : Monoid M
inst✝¹ : AddMonoid A
inst✝ : OrderedCancelCommMonoid α
s : Set α
hpos : ∀ x ∈ s, 1 ≤ x
h : IsPwo s
⊢ ∀ a₁ ∈ {l | ∀ x ∈ l, x ∈ s},
    ∀ a₂ ∈ {l | ∀ x ∈ l, x ∈ s}, List.SublistForall₂ (fun x x_1 => x ≤ x_1) a₁ a₂ → List.prod a₁ ≤ List.prod a₂

Next tactic:
exact fun l1 _ l2 hl2 h12 => h12.prod_le_prod' fun x hx => hpos x <| hl2 x hx
/-- Auxiliary definition for the `MonoidalClosed` instance on `Module R`.
(This is only a separate definition in order to speed up typechecking. )
-/
def monoidalClosedHomEquiv (M N P : ModuleCat.{u} R) :
    ((MonoidalCategory.tensorLeft M).obj N ⟶ P) ≃
      (N ⟶ ((linearCoyoneda R (ModuleCat R)).obj (op M)).obj P) where
  toFun f := LinearMap.compr₂ (TensorProduct.mk R N M) ((β_ N M).hom ≫ f)
  invFun f := (β_ M N).hom ≫ TensorProduct.lift f
  left_inv f := by
    

Proof state:
R : Type u
inst✝ : CommRing R
M N P : ModuleCat R
f : (MonoidalCategory.tensorLeft M).obj N ⟶ P
⊢ (fun f => (β_ M N).hom ≫ TensorProduct.lift f)
      ((fun f => LinearMap.compr₂ (TensorProduct.mk R ↑N ↑M) ((β_ N M).hom ≫ f)) f) =
    f

Next tactic:
apply TensorProduct.ext'
/-- Auxiliary definition for the `MonoidalClosed` instance on `Module R`.
(This is only a separate definition in order to speed up typechecking. )
-/
def monoidalClosedHomEquiv (M N P : ModuleCat.{u} R) :
    ((MonoidalCategory.tensorLeft M).obj N ⟶ P) ≃
      (N ⟶ ((linearCoyoneda R (ModuleCat R)).obj (op M)).obj P) where
  toFun f := LinearMap.compr₂ (TensorProduct.mk R N M) ((β_ N M).hom ≫ f)
  invFun f := (β_ M N).hom ≫ TensorProduct.lift f
  left_inv f := by
    apply TensorProduct.ext'
    

Proof state:
case H
R : Type u
inst✝ : CommRing R
M N P : ModuleCat R
f : (MonoidalCategory.tensorLeft M).obj N ⟶ P
⊢ ∀ (x : ↑M) (y : ↑N),
    ((fun f => (β_ M N).hom ≫ TensorProduct.lift f)
          ((fun f => LinearMap.compr₂ (TensorProduct.mk R ↑N ↑M) ((β_ N M).hom ≫ f)) f))
        (x ⊗ₜ[R] y) =
      f (x ⊗ₜ[R] y)

Next tactic:
intro m n
/-- Auxiliary definition for the `MonoidalClosed` instance on `Module R`.
(This is only a separate definition in order to speed up typechecking. )
-/
def monoidalClosedHomEquiv (M N P : ModuleCat.{u} R) :
    ((MonoidalCategory.tensorLeft M).obj N ⟶ P) ≃
      (N ⟶ ((linearCoyoneda R (ModuleCat R)).obj (op M)).obj P) where
  toFun f := LinearMap.compr₂ (TensorProduct.mk R N M) ((β_ N M).hom ≫ f)
  invFun f := (β_ M N).hom ≫ TensorProduct.lift f
  left_inv f := by
    apply TensorProduct.ext'
    intro m n
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    

Proof state:
case H
R : Type u
inst✝ : CommRing R
M N P : ModuleCat R
f : (MonoidalCategory.tensorLeft M).obj N ⟶ P
m : ↑M
n : ↑N
⊢ ((fun f => (β_ M N).hom ≫ TensorProduct.lift f)
        ((fun f => LinearMap.compr₂ (TensorProduct.mk R ↑N ↑M) ((β_ N M).hom ≫ f)) f))
      (m ⊗ₜ[R] n) =
    f (m ⊗ₜ[R] n)

Next tactic:
erw [coe_comp]
/-- Auxiliary definition for the `MonoidalClosed` instance on `Module R`.
(This is only a separate definition in order to speed up typechecking. )
-/
def monoidalClosedHomEquiv (M N P : ModuleCat.{u} R) :
    ((MonoidalCategory.tensorLeft M).obj N ⟶ P) ≃
      (N ⟶ ((linearCoyoneda R (ModuleCat R)).obj (op M)).obj P) where
  toFun f := LinearMap.compr₂ (TensorProduct.mk R N M) ((β_ N M).hom ≫ f)
  invFun f := (β_ M N).hom ≫ TensorProduct.lift f
  left_inv f := by
    apply TensorProduct.ext'
    intro m n
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    erw [coe_comp]
    

Proof state:
case H
R : Type u
inst✝ : CommRing R
M N P : ModuleCat R
f : (MonoidalCategory.tensorLeft M).obj N ⟶ P
m : ↑M
n : ↑N
⊢ (⇑(TensorProduct.lift ((fun f => LinearMap.compr₂ (TensorProduct.mk R ↑N ↑M) ((β_ N M).hom ≫ f)) f)) ∘ ⇑(β_ M N).hom)
      (m ⊗ₜ[R] n) =
    f (m ⊗ₜ[R] n)

Next tactic:
rw [Function.comp_apply]
/-- Auxiliary definition for the `MonoidalClosed` instance on `Module R`.
(This is only a separate definition in order to speed up typechecking. )
-/
def monoidalClosedHomEquiv (M N P : ModuleCat.{u} R) :
    ((MonoidalCategory.tensorLeft M).obj N ⟶ P) ≃
      (N ⟶ ((linearCoyoneda R (ModuleCat R)).obj (op M)).obj P) where
  toFun f := LinearMap.compr₂ (TensorProduct.mk R N M) ((β_ N M).hom ≫ f)
  invFun f := (β_ M N).hom ≫ TensorProduct.lift f
  left_inv f := by
    apply TensorProduct.ext'
    intro m n
    -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    erw [coe_comp]
    rw [Function.comp_apply]
    -- This used to be `rw` and was longer (?), but we need `erw` after leanprover/lean4#2644
    

Proof state:
case H
R : Type u
inst✝ : CommRing R
M N P : ModuleCat R
f : (MonoidalCategory.tensorLeft M).obj N ⟶ P
m : ↑M
n : ↑N
⊢ (TensorProduct.lift ((fun f => LinearMap.compr₂ (TensorProduct.mk R ↑N ↑M) ((β_ N M).hom ≫ f)) f))
      ((β_ M N).hom (m ⊗ₜ[R] n)) =
    f (m ⊗ₜ[R] n)

Next tactic:
erw [MonoidalCategory.braiding_hom_apply, TensorProduct.lift.tmul]
instance : MonoidalClosed (ModuleCat.{u} R) where
  closed M :=
    { isAdj :=
        { right := (linearCoyoneda R (ModuleCat.{u} R)).obj (op M)
          adj := Adjunction.mkOfHomEquiv
            { homEquiv := fun N P => monoidalClosedHomEquiv M N P
              -- porting note: this proof was automatic in mathlib3
              homEquiv_naturality_left_symm := by
                

Proof state:
R : Type u
inst✝ : CommRing R
M : ModuleCat R
⊢ ∀ {X' X Y : ModuleCat R} (f : X' ⟶ X) (g : X ⟶ ((linearCoyoneda R (ModuleCat R)).obj (op M)).obj Y),
    ((fun N P => monoidalClosedHomEquiv M N P) X' Y).symm (f ≫ g) =
      (MonoidalCategory.tensorLeft M).map f ≫ ((fun N P => monoidalClosedHomEquiv M N P) X Y).symm g

Next tactic:
intros
instance : MonoidalClosed (ModuleCat.{u} R) where
  closed M :=
    { isAdj :=
        { right := (linearCoyoneda R (ModuleCat.{u} R)).obj (op M)
          adj := Adjunction.mkOfHomEquiv
            { homEquiv := fun N P => monoidalClosedHomEquiv M N P
              -- porting note: this proof was automatic in mathlib3
              homEquiv_naturality_left_symm := by
                intros
                

Proof state:
R : Type u
inst✝ : CommRing R
M X'✝ X✝ Y✝ : ModuleCat R
f✝ : X'✝ ⟶ X✝
g✝ : X✝ ⟶ ((linearCoyoneda R (ModuleCat R)).obj (op M)).obj Y✝
⊢ ((fun N P => monoidalClosedHomEquiv M N P) X'✝ Y✝).symm (f✝ ≫ g✝) =
    (MonoidalCategory.tensorLeft M).map f✝ ≫ ((fun N P => monoidalClosedHomEquiv M N P) X✝ Y✝).symm g✝

Next tactic:
apply TensorProduct.ext'
instance : MonoidalClosed (ModuleCat.{u} R) where
  closed M :=
    { isAdj :=
        { right := (linearCoyoneda R (ModuleCat.{u} R)).obj (op M)
          adj := Adjunction.mkOfHomEquiv
            { homEquiv := fun N P => monoidalClosedHomEquiv M N P
              -- porting note: this proof was automatic in mathlib3
              homEquiv_naturality_left_symm := by
                intros
                apply TensorProduct.ext'
                

Proof state:
case H
R : Type u
inst✝ : CommRing R
M X'✝ X✝ Y✝ : ModuleCat R
f✝ : X'✝ ⟶ X✝
g✝ : X✝ ⟶ ((linearCoyoneda R (ModuleCat R)).obj (op M)).obj Y✝
⊢ ∀ (x : ↑M) (y : ↑X'✝),
    (((fun N P => monoidalClosedHomEquiv M N P) X'✝ Y✝).symm (f✝ ≫ g✝)) (x ⊗ₜ[R] y) =
      ((MonoidalCategory.tensorLeft M).map f✝ ≫ ((fun N P => monoidalClosedHomEquiv M N P) X✝ Y✝).symm g✝) (x ⊗ₜ[R] y)

Next tactic:
intro m n
instance : MonoidalClosed (ModuleCat.{u} R) where
  closed M :=
    { isAdj :=
        { right := (linearCoyoneda R (ModuleCat.{u} R)).obj (op M)
          adj := Adjunction.mkOfHomEquiv
            { homEquiv := fun N P => monoidalClosedHomEquiv M N P
              -- porting note: this proof was automatic in mathlib3
              homEquiv_naturality_left_symm := by
                intros
                apply TensorProduct.ext'
                intro m n
                

Proof state:
case H
R : Type u
inst✝ : CommRing R
M X'✝ X✝ Y✝ : ModuleCat R
f✝ : X'✝ ⟶ X✝
g✝ : X✝ ⟶ ((linearCoyoneda R (ModuleCat R)).obj (op M)).obj Y✝
m : ↑M
n : ↑X'✝
⊢ (((fun N P => monoidalClosedHomEquiv M N P) X'✝ Y✝).symm (f✝ ≫ g✝)) (m ⊗ₜ[R] n) =
    ((MonoidalCategory.tensorLeft M).map f✝ ≫ ((fun N P => monoidalClosedHomEquiv M N P) X✝ Y✝).symm g✝) (m ⊗ₜ[R] n)

Next tactic:
rfl
/-- Describes the counit of the adjunction `M ⊗ - ⊣ Hom(M, -)`. Given an `R`-module `N` this
should give a map `M ⊗ Hom(M, N) ⟶ N`, so we flip the order of the arguments in the identity map
`Hom(M, N) ⟶ (M ⟶ N)` and uncurry the resulting map `M ⟶ Hom(M, N) ⟶ N.` -/
theorem ihom_ev_app (M N : ModuleCat.{u} R) :
    (ihom.ev M).app N = TensorProduct.uncurry _ _ _ _ LinearMap.id.flip := by
  

Proof state:
R : Type u
inst✝ : CommRing R
M N : ModuleCat R
⊢ (ihom.ev M).app N = (TensorProduct.uncurry R (↑M) (↑M →ₗ[R] ↑N) ↑N) (LinearMap.flip LinearMap.id)

Next tactic:
apply TensorProduct.ext'
/-- Describes the counit of the adjunction `M ⊗ - ⊣ Hom(M, -)`. Given an `R`-module `N` this
should give a map `M ⊗ Hom(M, N) ⟶ N`, so we flip the order of the arguments in the identity map
`Hom(M, N) ⟶ (M ⟶ N)` and uncurry the resulting map `M ⟶ Hom(M, N) ⟶ N.` -/
theorem ihom_ev_app (M N : ModuleCat.{u} R) :
    (ihom.ev M).app N = TensorProduct.uncurry _ _ _ _ LinearMap.id.flip := by
  apply TensorProduct.ext'
  

Proof state:
case H
R : Type u
inst✝ : CommRing R
M N : ModuleCat R
⊢ ∀ (x : ↑M) (y : ↑((ihom M).obj N)),
    ((ihom.ev M).app N) (x ⊗ₜ[R] y) =
      ((TensorProduct.uncurry R (↑M) (↑M →ₗ[R] ↑N) ↑N) (LinearMap.flip LinearMap.id)) (x ⊗ₜ[R] y)

Next tactic:
apply ModuleCat.monoidalClosed_uncurry
/-- Induct on two `EReal`s by performing case splits on the sign of one whenever the other is
infinite. -/
@[elab_as_elim]
theorem induction₂ {P : EReal → EReal → Prop} (top_top : P ⊤ ⊤) (top_pos : ∀ x : ℝ, 0 < x → P ⊤ x)
    (top_zero : P ⊤ 0) (top_neg : ∀ x : ℝ, x < 0 → P ⊤ x) (top_bot : P ⊤ ⊥)
    (pos_top : ∀ x : ℝ, 0 < x → P x ⊤) (pos_bot : ∀ x : ℝ, 0 < x → P x ⊥) (zero_top : P 0 ⊤)
    (coe_coe : ∀ x y : ℝ, P x y) (zero_bot : P 0 ⊥) (neg_top : ∀ x : ℝ, x < 0 → P x ⊤)
    (neg_bot : ∀ x : ℝ, x < 0 → P x ⊥) (bot_top : P ⊥ ⊤) (bot_pos : ∀ x : ℝ, 0 < x → P ⊥ x)
    (bot_zero : P ⊥ 0) (bot_neg : ∀ x : ℝ, x < 0 → P ⊥ x) (bot_bot : P ⊥ ⊥) : ∀ x y, P x y
  | ⊥, ⊥ => bot_bot
  | ⊥, (y : ℝ) => by
    

Proof state:
P : EReal → EReal → Prop
top_top : P ⊤ ⊤
top_pos : ∀ (x : ℝ), 0 < x → P ⊤ ↑x
top_zero : P ⊤ 0
top_neg : ∀ x < 0, P ⊤ ↑x
top_bot : P ⊤ ⊥
pos_top : ∀ (x : ℝ), 0 < x → P ↑x ⊤
pos_bot : ∀ (x : ℝ), 0 < x → P ↑x ⊥
zero_top : P 0 ⊤
coe_coe : ∀ (x y : ℝ), P ↑x ↑y
zero_bot : P 0 ⊥
neg_top : ∀ x < 0, P ↑x ⊤
neg_bot : ∀ x < 0, P ↑x ⊥
bot_top : P ⊥ ⊤
bot_pos : ∀ (x : ℝ), 0 < x → P ⊥ ↑x
bot_zero : P ⊥ 0
bot_neg : ∀ x < 0, P ⊥ ↑x
bot_bot : P ⊥ ⊥
y : ℝ
⊢ P ⊥ ↑y

Next tactic:
rcases lt_trichotomy y 0 with (hy | rfl | hy)