lean4-htt/src/Init/Data/Function.lean
2025-10-16 20:27:46 +00:00

136 lines
5 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
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