-- ToMathlib/Control/Monad/Equiv.lean

import ToMathlib.Control.Monad.Hom

import Mathlib.Logic.Function.Defs

structure NatEquiv (m : Type u → Type v) (n : Type u → Type w) where
  toFun : {α : Type u} → m α → n α
  invFun : {α : Type u} → n α → m α
  left_inv : ∀ {α}, Function.LeftInverse (@invFun α) (@toFun α) := by admit /- proof elided -/

namespace NatEquiv

variable {m : Type u → Type v} {n : Type u → Type w} {p : Type u → Type z}

end NatEquiv

structure PureEquiv (m : Type u → Type v) [Pure m] (n : Type u → Type w) [Pure n]
    extends NatEquiv m n where
  map_pure' {α : Type u} (x : α) : toFun (pure x) = (pure x : n α)

namespace PureEquiv

variable {m : Type u → Type v} [Pure m] {n : Type u → Type w} [Pure n]

-- Repository definitions used:
content: structure NatHom (m : Type u → Type v) (n : Type u → Type w) where
  toFun : {α : Type u} → m α → n α

-- Repository lemmas used:
content: theorem List.getElem_append_left{α : Type u_1} {l₁ l₂ : List α} {i : Nat} (hn : i < l₁.length) :\n(l₁ ++ l₂)[i] = l₁[i]

-- Local definitions used:
content: structure NatEquiv (m : Type u → Type v) (n : Type u → Type w) where
  toFun : {α : Type u} → m α → n α
  invFun : {α : Type u} → n α → m α
  left_inv : ∀ {α}, Function.LeftInverse (@invFun α) (@toFun α) := by admit /- proof elided -/

content: structure PureEquiv (m : Type u → Type v) [Pure m] (n : Type u → Type w) [Pure n]
    extends NatEquiv m n where
  map_pure' {α : Type u} (x : α) : toFun (pure x) = (pure x : n α)

-- Local lemmas used:

-- Target theorem and proof:
@[simp]
lemma map_pure_inv (f : PureEquiv m n) {α : Type u} (x : α) :
    f.invFun (pure x) = (pure x : m α)
:= by
  have h1 : f.toFun (f.invFun (pure x)) = pure x := f.right_inv (pure x)
  have h2 : f.toFun (pure x) = pure x := f.map_pure' x
  have h3 : f.toFun (f.invFun (pure x)) = f.toFun (pure x) := by rw [h1, h2]
  exact Function.LeftInverse.injective f.left_inv h3