/-- **The Eckmann–Hilton argument.** Suppose a type carries two binary operations `m₁`, `m₂`
with units `e₁`, `e₂`, satisfying the interchange law
`m₁ (m₂ a b) (m₂ c d) = m₂ (m₁ a c) (m₁ b d)`. Then the units agree, the operations agree, and
the operation is commutative. (Mathlib: `EckmannHilton.one`, `EckmannHilton.mul`,
`EckmannHilton.mul_comm`.)
Proof. Interchange with `(a, b, c, d) = (e₂, e₁, e₁, e₂)` gives `e₁ = e₂ =: e`. Then
`m₁ a b = m₁ (m₂ a e) (m₂ e b) = m₂ (m₁ a e) (m₁ e b) = m₂ a b`, and
`m₁ a b = m₁ (m₂ e a) (m₂ b e) = m₂ (m₁ e b) (m₁ a e) = m₂ b a = m₁ b a`. -/
theorem eckmann_hilton {X : Type u} (m₁ m₂ : X → X → X) (e₁ e₂ : X)
(h₁l : ∀ x, m₁ e₁ x = x) (h₁r : ∀ x, m₁ x e₁ = x)
(h₂l : ∀ x, m₂ e₂ x = x) (h₂r : ∀ x, m₂ x e₂ = x)
(interchange : ∀ a b c d, m₁ (m₂ a b) (m₂ c d) = m₂ (m₁ a c) (m₁ b d)) :
e₁ = e₂ ∧ m₁ = m₂ ∧ ∀ a b, m₁ a b = m₁ b a := by
have units : e₁ = e₂ := by
have h := interchange e₂ e₁ e₁ e₂
rw [h₂l, h₂r, h₁l, h₁r, h₁l, h₂l] at h
exact h
subst units
have same : m₁ = m₂ := by
funext a b
calc m₁ a b = m₁ (m₂ a e₁) (m₂ e₁ b) := by rw [h₂r, h₂l]
_ = m₂ (m₁ a e₁) (m₁ e₁ b) := interchange a e₁ e₁ b
_ = m₂ a b := by rw [h₁r, h₁l]
refine ⟨rfl, same, fun a b => ?_⟩
calc m₁ a b = m₁ (m₂ e₁ a) (m₂ b e₁) := by rw [h₂l, h₂r]
_ = m₂ (m₁ e₁ b) (m₁ a e₁) := interchange e₁ a b e₁
_ = m₂ b a := by rw [h₁l, h₁r]
_ = m₁ b a := by rw [same]