136 lines
5 KiB
Text
136 lines
5 KiB
Text
/-
|
||
Copyright (c) 2024 Lean FRO. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Kim Morrison
|
||
-/
|
||
module
|
||
prelude
|
||
public import Init.Grind.Tactics
|
||
public section
|
||
namespace Function
|
||
|
||
/--
|
||
Transforms a function from pairs into an equivalent two-parameter function.
|
||
|
||
Examples:
|
||
* `Function.curry (fun (x, y) => x + y) 3 5 = 8`
|
||
* `Function.curry Prod.swap 3 "five" = ("five", 3)`
|
||
-/
|
||
@[inline, expose]
|
||
def curry : (α × β → φ) → α → β → φ := fun f a b => f (a, b)
|
||
|
||
/--
|
||
Transforms a two-parameter function into an equivalent function from pairs.
|
||
|
||
Examples:
|
||
* `Function.uncurry List.drop (1, ["a", "b", "c"]) = ["b", "c"]`
|
||
* `[("orange", 2), ("android", 3) ].map (Function.uncurry String.take) = ["or", "and"]`
|
||
-/
|
||
@[inline, expose]
|
||
def uncurry : (α → β → φ) → α × β → φ := fun f a => f a.1 a.2
|
||
|
||
@[simp, grind =]
|
||
theorem curry_uncurry (f : α → β → φ) : curry (uncurry f) = f :=
|
||
rfl
|
||
|
||
@[simp, grind =]
|
||
theorem uncurry_curry (f : α × β → φ) : uncurry (curry f) = f :=
|
||
funext fun ⟨_a, _b⟩ => rfl
|
||
|
||
@[simp, grind =]
|
||
theorem uncurry_apply_pair {α β γ} (f : α → β → γ) (x : α) (y : β) : uncurry f (x, y) = f x y :=
|
||
rfl
|
||
|
||
@[simp, grind =]
|
||
theorem curry_apply {α β γ} (f : α × β → γ) (x : α) (y : β) : curry f x y = f (x, y) :=
|
||
rfl
|
||
|
||
/-- A function `f : α → β` is called injective if `f x = f y` implies `x = y`. -/
|
||
@[expose]
|
||
def Injective (f : α → β) : Prop :=
|
||
∀ ⦃a₁ a₂⦄, f a₁ = f a₂ → a₁ = a₂
|
||
|
||
theorem Injective.comp {α β γ} {g : β → γ} {f : α → β} (hg : Injective g) (hf : Injective f) :
|
||
Injective (g ∘ f) := fun _a₁ _a₂ => fun h => hf (hg h)
|
||
|
||
/-- A function `f : α → β` is called surjective if every `b : β` is equal to `f a`
|
||
for some `a : α`. -/
|
||
@[expose]
|
||
def Surjective (f : α → β) : Prop :=
|
||
∀ b, Exists fun a => f a = b
|
||
|
||
theorem Surjective.comp {α β γ} {g : β → γ} {f : α → β} (hg : Surjective g) (hf : Surjective f) :
|
||
Surjective (g ∘ f) := fun c : γ =>
|
||
Exists.elim (hg c) fun b hb =>
|
||
Exists.elim (hf b) fun a ha =>
|
||
Exists.intro a (show g (f a) = c from Eq.trans (congrArg g ha) hb)
|
||
|
||
/-- `LeftInverse g f` means that `g` is a left inverse to `f`. That is, `g ∘ f = id`. -/
|
||
@[expose, grind]
|
||
def LeftInverse {α β} (g : β → α) (f : α → β) : Prop :=
|
||
∀ x, g (f x) = x
|
||
|
||
/-- `HasLeftInverse f` means that `f` has an unspecified left inverse. -/
|
||
@[expose]
|
||
def HasLeftInverse {α β} (f : α → β) : Prop :=
|
||
Exists fun finv : β → α => LeftInverse finv f
|
||
|
||
/-- `RightInverse g f` means that `g` is a right inverse to `f`. That is, `f ∘ g = id`. -/
|
||
@[expose, grind]
|
||
def RightInverse {α β} (g : β → α) (f : α → β) : Prop :=
|
||
LeftInverse f g
|
||
|
||
/-- `HasRightInverse f` means that `f` has an unspecified right inverse. -/
|
||
@[expose]
|
||
def HasRightInverse {α β} (f : α → β) : Prop :=
|
||
Exists fun finv : β → α => RightInverse finv f
|
||
|
||
theorem LeftInverse.injective {α β} {g : β → α} {f : α → β} : LeftInverse g f → Injective f :=
|
||
fun h a b faeqfb => ((h a).symm.trans (congrArg g faeqfb)).trans (h b)
|
||
|
||
theorem HasLeftInverse.injective {α β} {f : α → β} : HasLeftInverse f → Injective f := fun h =>
|
||
Exists.elim h fun _finv inv => inv.injective
|
||
|
||
theorem rightInverse_of_injective_of_leftInverse {α β} {f : α → β} {g : β → α} (injf : Injective f)
|
||
(lfg : LeftInverse f g) : RightInverse f g := fun x =>
|
||
have h : f (g (f x)) = f x := lfg (f x)
|
||
injf h
|
||
|
||
theorem RightInverse.surjective {α β} {f : α → β} {g : β → α} (h : RightInverse g f) : Surjective f :=
|
||
fun y => ⟨g y, h y⟩
|
||
|
||
theorem HasRightInverse.surjective {α β} {f : α → β} : HasRightInverse f → Surjective f
|
||
| ⟨_finv, inv⟩ => inv.surjective
|
||
|
||
theorem leftInverse_of_surjective_of_rightInverse {α β} {f : α → β} {g : β → α} (surjf : Surjective f)
|
||
(rfg : RightInverse f g) : LeftInverse f g := fun y =>
|
||
Exists.elim (surjf y) fun x hx => ((hx ▸ rfl : f (g y) = f (g (f x))).trans (Eq.symm (rfg x) ▸ rfl)).trans hx
|
||
|
||
theorem injective_id : Injective (@id α) := fun _a₁ _a₂ h => h
|
||
|
||
theorem surjective_id : Surjective (@id α) := fun a => ⟨a, rfl⟩
|
||
|
||
variable {f : α → β}
|
||
|
||
theorem Injective.eq_iff (I : Injective f) {a b : α} : f a = f b ↔ a = b :=
|
||
⟨@I _ _, congrArg f⟩
|
||
|
||
theorem Injective.eq_iff' (I : Injective f) {a b : α} {c : β} (h : f b = c) : f a = c ↔ a = b :=
|
||
h ▸ I.eq_iff
|
||
|
||
theorem Injective.ne (hf : Injective f) {a₁ a₂ : α} : a₁ ≠ a₂ → f a₁ ≠ f a₂ :=
|
||
mt fun h ↦ hf h
|
||
|
||
theorem Injective.ne_iff (hf : Injective f) {x y : α} : f x ≠ f y ↔ x ≠ y :=
|
||
⟨mt <| congrArg f, hf.ne⟩
|
||
|
||
theorem Injective.ne_iff' (hf : Injective f) {x y : α} {z : β} (h : f y = z) : f x ≠ z ↔ x ≠ y :=
|
||
h ▸ hf.ne_iff
|
||
|
||
protected theorem LeftInverse.id {α β} {g : β → α} {f : α → β} (h : LeftInverse g f) : g ∘ f = id :=
|
||
funext h
|
||
|
||
protected theorem RightInverse.id {α β} {g : β → α} {f : α → β} (h : RightInverse g f) : f ∘ g = id :=
|
||
funext h
|
||
|
||
end Function
|