doc-next-gen

Mathlib.Control.Basic

Module docstring

{"Extends the theory on functors, applicatives and monads. "}

zipWithM definition
{α₁ α₂ φ : Type u} (f : α₁ → α₂ → F φ) : ∀ (_ : List α₁) (_ : List α₂), F (List φ)
Full source
/-- A generalization of `List.zipWith` which combines list elements with an `Applicative`. -/
def zipWithM {α₁ α₂ φ : Type u} (f : α₁ → α₂ → F φ) : ∀ (_ : List α₁) (_ : List α₂), F (List φ)
  | x :: xs, y :: ys => (· :: ·) <$> f x y <*> zipWithM f xs ys
  | _, _ => pure []
Applicative zipWith for lists
Informal description
Given a function $f : \alpha_1 \to \alpha_2 \to F \phi$ where $F$ is an applicative functor, the function `zipWithM` applies $f$ pairwise to elements of two lists $[x_1, \dots, x_n]$ and $[y_1, \dots, y_m]$, resulting in a computation $F [\phi]$ that produces a list of results. If the lists have different lengths, the computation returns the empty list. More precisely: - For lists `x :: xs` and `y :: ys`, it applies `f x y` and combines the result with the recursive application of `zipWithM f xs ys` using the applicative sequencing operation. - For any other case (empty lists or mismatched lengths), it returns `pure []`.
zipWithM' definition
(f : α → β → F γ) : List α → List β → F PUnit
Full source
/-- Like `zipWithM` but evaluates the result as it traverses the lists using `*>`. -/
def zipWithM' (f : α → β → F γ) : List α → List β → F PUnit
  | x :: xs, y :: ys => f x y *> zipWithM' f xs ys
  | [], _ => pure PUnit.unit
  | _, [] => pure PUnit.unit
Sequential zip with monadic function (discarding results)
Informal description
Given a function `f : α → β → F γ` and two lists `xs : List α` and `ys : List β`, the function `zipWithM'` applies `f` pairwise to the elements of `xs` and `ys`, evaluating the results sequentially using the `*>` operator (which discards the result of the left action and keeps the right action). The final result is of type `F PUnit`, where `PUnit` is the singleton type. If the lists are of unequal length, the remaining elements are ignored, and the result is `pure PUnit.unit`.
pure_id'_seq theorem
(x : F α) : (pure fun x => x) <*> x = x
Full source
@[simp]
theorem pure_id'_seq (x : F α) : (pure fun x => x) <*> x = x :=
  pure_id_seq x
Applicative Identity Law: Pure Identity Sequenced with Computation Yields Original Computation
Informal description
For any applicative functor $F$ and any computation $x : F \alpha$, applying the identity function (lifted via `pure`) to $x$ using the applicative sequencing operation `<*>` yields $x$ itself, i.e., $(\text{pure} \ \text{id}) \ <*> \ x = x$.
seq_map_assoc theorem
(x : F (α → β)) (f : γ → α) (y : F γ) : x <*> f <$> y = (· ∘ f) <$> x <*> y
Full source
@[functor_norm]
theorem seq_map_assoc (x : F (α → β)) (f : γ → α) (y : F γ) :
    x <*> f <$> y = (· ∘ f) <$> x(· ∘ f) <$> x <*> y := by
  simp only [← pure_seq]
  simp only [seq_assoc, Function.comp, seq_pure, ← comp_map]
  simp [pure_seq]
  rfl
Associativity of Sequential Mapping in Applicative Functors
Informal description
For any applicative functor $F$, given an element $x \in F(\alpha \to \beta)$, a function $f \colon \gamma \to \alpha$, and an element $y \in F(\gamma)$, the following equality holds: \[ x \mathbin{\texttt{<*>}} (f \mathbin{\texttt{<$>}} y) = (\cdot \circ f) \mathbin{\texttt{<$>}} x \mathbin{\texttt{<*>}} y. \] Here, $\texttt{<*>}$ denotes the applicative sequencing operation, and $\texttt{<$>}$ denotes the functorial map operation.
map_seq theorem
(f : β → γ) (x : F (α → β)) (y : F α) : f <$> (x <*> y) = (f ∘ ·) <$> x <*> y
Full source
@[functor_norm]
theorem map_seq (f : β → γ) (x : F (α → β)) (y : F α) :
    f <$> (x <*> y) = (f ∘ ·) <$> x(f ∘ ·) <$> x <*> y := by
  simp only [← pure_seq]; simp [seq_assoc]
Composition of Map and Sequential Application in Applicative Functors
Informal description
For any function $f : \beta \to \gamma$, any applicative functor $F$ containing a function $x : F(\alpha \to \beta)$, and any $y : F\alpha$, the following equality holds: $$ f \text{ <\$> } (x \text{ <*> } y) = (f \circ \cdot) \text{ <\$> } x \text{ <*> } y $$ where `<$>` denotes the `map` operation and `<*>` denotes the `seq` (sequential application) operation in the applicative functor $F$.
seq_bind_eq theorem
(x : m α) {g : β → m γ} {f : α → β} : f <$> x >>= g = x >>= g ∘ f
Full source
theorem seq_bind_eq (x : m α) {g : β → m γ} {f : α → β} :
    f <$> xf <$> x >>= g = x >>= g ∘ f :=
  show bind (f <$> x) g = bind x (g ∘ f) by
    rw [← bind_pure_comp, bind_assoc]
    simp [pure_bind, Function.comp_def]
Monadic Map-Bind Composition: $\text{map}\,f\,x \gg\!\!= g = x \gg\!\!= (g \circ f)$
Informal description
For any monadic value $x : m \alpha$ and functions $f : \alpha \to \beta$ and $g : \beta \to m \gamma$, the composition of mapping $f$ over $x$ followed by binding $g$ is equal to binding the composition $g \circ f$ to $x$ directly. That is, $$ \text{map}\,f\,x \gg\!\!= g = x \gg\!\!= (g \circ f). $$
fish_pure theorem
{α β} (f : α → m β) : f >=> pure = f
Full source
@[functor_norm]
theorem fish_pure {α β} (f : α → m β) : f >=> pure = f := by
  simp +unfoldPartialApp only [(· >=> ·), functor_norm]
Right Identity Law for Kleisli Composition
Informal description
For any function $f \colon \alpha \to m \beta$ in a monad $m$, the composition of $f$ with the pure function (using the Kleisli composition `>=>`) is equal to $f$ itself, i.e., $f \mathbin{>=>} \text{pure} = f$.
fish_pipe theorem
{α β} (f : α → m β) : pure >=> f = f
Full source
@[functor_norm]
theorem fish_pipe {α β} (f : α → m β) : purepure >=> f = f := by
  simp +unfoldPartialApp only [(· >=> ·), functor_norm]
Left Identity of Kleisli Composition with Pure Function
Informal description
For any monad `m` and function `f : α → m β`, the composition of the pure function followed by `f` under the Kleisli composition (`>=>`) is equal to `f` itself. That is, $\text{pure} \mathbin{>=>} f = f$.
fish_assoc theorem
{α β γ φ} (f : α → m β) (g : β → m γ) (h : γ → m φ) : (f >=> g) >=> h = f >=> g >=> h
Full source
@[functor_norm]
theorem fish_assoc {α β γ φ} (f : α → m β) (g : β → m γ) (h : γ → m φ) :
    (f >=> g) >=> h = f >=> g >=> h := by
  simp +unfoldPartialApp only [(· >=> ·), functor_norm]
Associativity of Kleisli Composition
Informal description
For any monad `m` and functions $f : \alpha \to m \beta$, $g : \beta \to m \gamma$, and $h : \gamma \to m \phi$, the composition of Kleisli arrows is associative, i.e., $(f \gg\!\!> g) \gg\!\!> h = f \gg\!\!> (g \gg\!\!> h)$.
List.mapAccumRM definition
(f : α → β' → m' (β' × γ')) : β' → List α → m' (β' × List γ')
Full source
/-- Takes a value `β` and `List α` and accumulates pairs according to a monadic function `f`.
Accumulation occurs from the right (i.e., starting from the tail of the list). -/
def List.mapAccumRM (f : α → β' → m' (β' × γ')) : β' → List α → m' (β' × List γ')
  | a, [] => pure (a, [])
  | a, x :: xs => do
    let (a', ys) ← List.mapAccumRM f a xs
    let (a'', y) ← f x a'
    pure (a'', y :: ys)
Right-to-left monadic accumulation over a list
Informal description
Given a monadic function $f : \alpha \to \beta' \to m' (\beta' \times \gamma')$, an initial accumulator value $a : \beta'$, and a list $[x_1, \ldots, x_n] : \text{List } \alpha$, the function `List.mapAccumRM` processes the list from right to left (starting from the tail). For each element $x_i$, it applies $f$ to $x_i$ and the current accumulator value, resulting in a new accumulator value and a transformed element $y_i$. The final result is a pair consisting of the last accumulator value and the list of transformed elements $[y_1, \ldots, y_n]$.
List.mapAccumLM definition
(f : β' → α → m' (β' × γ')) : β' → List α → m' (β' × List γ')
Full source
/-- Takes a value `β` and `List α` and accumulates pairs according to a monadic function `f`.
Accumulation occurs from the left (i.e., starting from the head of the list). -/
def List.mapAccumLM (f : β' → α → m' (β' × γ')) : β' → List α → m' (β' × List γ')
  | a, [] => pure (a, [])
  | a, x :: xs => do
    let (a', y) ← f a x
    let (a'', ys) ← List.mapAccumLM f a' xs
    pure (a'', y :: ys)
Left-accumulating monadic map over a list
Informal description
Given a monadic function $f : \beta' \times \alpha \to m' (\beta' \times \gamma')$, an initial accumulator value $a : \beta'$, and a list $[x_1, \ldots, x_n] : \text{List } \alpha$, the function `List.mapAccumLM` processes the list from left to right, applying $f$ to each element $x_i$ along with the current accumulator value, and collects the results into a pair consisting of the final accumulator value and the list of outputs $[y_1, \ldots, y_n] : \text{List } \gamma'$.
joinM_map_map theorem
{α β : Type u} (f : α → β) (a : m (m α)) : joinM (Functor.map f <$> a) = f <$> joinM a
Full source
theorem joinM_map_map {α β : Type u} (f : α → β) (a : m (m α)) :
    joinM (Functor.mapFunctor.map f <$> a) = f <$> joinM a := by
  simp only [joinM, (· ∘ ·), id, ← bind_pure_comp, bind_assoc, map_bind, pure_bind]
Naturality of Monadic Join with Respect to Mapping
Informal description
For any monad `m`, types `α` and `β`, function `f : α → β`, and nested monadic value `a : m (m α)`, the following equality holds: $$\text{joinM} (\text{map } f <$> a) = \text{map } f (\text{joinM } a)$$ where `<$>` is the infix notation for `Functor.map`, and `joinM` is the monadic join operation.
joinM_map_joinM theorem
{α : Type u} (a : m (m (m α))) : joinM (joinM <$> a) = joinM (joinM a)
Full source
theorem joinM_map_joinM {α : Type u} (a : m (m (m α))) : joinM (joinMjoinM <$> a) = joinM (joinM a) := by
  simp only [joinM, (· ∘ ·), id, map_bind, ← bind_pure_comp, bind_assoc, pure_bind]
Monadic Join Associativity: $\text{joinM}(\text{map joinM } a) = \text{joinM}(\text{joinM } a)$
Informal description
For any monad `m` and any triply-nested monadic value `a : m (m (m α))`, the following equality holds: \[ \text{joinM}(\text{map joinM } a) = \text{joinM}(\text{joinM } a) \] where `joinM` is the monadic join operation and `map` is the functorial map operation.
joinM_map_pure theorem
{α : Type u} (a : m α) : joinM (pure <$> a) = a
Full source
@[simp]
theorem joinM_map_pure {α : Type u} (a : m α) : joinM (purepure <$> a) = a := by
  simp only [joinM, (· ∘ ·), id, map_bind, ← bind_pure_comp, bind_assoc, pure_bind, bind_pure]
Monadic Join-Pure Identity: $\mathrm{joinM}(\mathrm{pure} \circ a) = a$
Informal description
For any monad `m` and any monadic value `a : m α`, flattening the result of mapping the pure function over `a` yields `a` itself, i.e., $\mathrm{joinM}(\mathrm{pure} \circ a) = a$.
joinM_pure theorem
{α : Type u} (a : m α) : joinM (pure a) = a
Full source
@[simp]
theorem joinM_pure {α : Type u} (a : m α) : joinM (pure a) = a :=
  LawfulMonad.pure_bind a id
Monadic Join of Pure is Identity
Informal description
For any monad `m` and any value `a : m α`, the monadic join operation applied to the pure embedding of `a` returns `a`, i.e., $\text{joinM}(\text{pure}(a)) = a$.
succeeds definition
{α} (x : F α) : F Bool
Full source
/-- Returns `pure true` if the computation succeeds and `pure false` otherwise. -/
def succeeds {α} (x : F α) : F Bool :=
  Functor.mapConst true x <|> pure false
Success predicate for a computation
Informal description
Given a computation `x` of type `F α`, the function returns a computation that evaluates to `pure true` if `x` succeeds and `pure false` otherwise.
tryM definition
{α} (x : F α) : F Unit
Full source
/-- Attempts to perform the computation, but fails silently if it doesn't succeed. -/
def tryM {α} (x : F α) : F Unit :=
  Functor.mapConst () x <|> pure ()
Silent attempt computation
Informal description
The function `tryM` takes a computation `x` of type `F α` (where `F` is a functor) and returns a computation of type `F Unit` that attempts to perform `x` but discards its result, returning `()` (unit) regardless of success or failure. If `x` fails, the function silently continues without propagating the error.
try? definition
{α} (x : F α) : F (Option α)
Full source
/-- Attempts to perform the computation, and returns `none` if it doesn't succeed. -/
def try? {α} (x : F α) : F (Option α) :=
  somesome <$> x <|> pure none
Attempt computation with optional result
Informal description
Given a computation `x` of type `F α`, the operation `try?` attempts to perform the computation and returns `some a` if it succeeds (where `a` is the result of the computation), or `none` if it fails. This is implemented as `some <$> x <|> pure none`, meaning it first tries to map the result of `x` to `some`, and if that fails, it returns `none`.
guard_true theorem
{h : Decidable True} : @guard F _ True h = pure ()
Full source
@[simp]
theorem guard_true {h : Decidable True} : @guard F _ True h = pure () := by simp [guard, if_pos]
Guard on True Yields Pure Unit
Informal description
For any monad `F` and given a decidable instance `h` for `True`, the guard operation `guard True` is equal to the pure unit operation `pure ()`.
guard_false theorem
{h : Decidable False} : @guard F _ False h = failure
Full source
@[simp]
theorem guard_false {h : Decidable False} : @guard F _ False h = failure := by
  simp [guard, if_neg not_false]
Guard of False is Failure
Informal description
For any monad `F` with a `Decidable` instance for `False`, the `guard` operation on `False` evaluates to the `failure` computation.
Sum.bind definition
{α β} : e ⊕ α → (α → e ⊕ β) → e ⊕ β
Full source
/-- The monadic `bind` operation for `Sum`. -/
protected def bind {α β} : e ⊕ α → (α → e ⊕ β) → e ⊕ β
  | inl x, _ => inl x
  | inr x, f => f x
Bind operation for sum type
Informal description
The monadic bind operation for the sum type `e ⊕ α` takes a value of type `e ⊕ α` and a function `f : α → e ⊕ β`, and returns a value of type `e ⊕ β`. If the input is `inl x` (an error of type `e`), it propagates the error. If the input is `inr x` (a success of type `α`), it applies the function `f` to `x`.
Sum.instMonad_mathlib instance
: Monad (Sum.{v, u} e)
Full source
instance : Monad (Sum.{v, u} e) where
  pure := @Sum.inr e
  bind := @Sum.bind e
Monad Structure on Sum Types
Informal description
For any type $e$, the sum type $e \oplus \alpha$ forms a monad, where the monadic operations are defined to propagate errors (left case) or apply functions to successful values (right case).
Sum.instLawfulFunctor_mathlib instance
: LawfulFunctor (Sum.{v, u} e)
Full source
instance : LawfulFunctor (Sum.{v, u} e) := by
  constructor <;> intros <;> (try casesm Sum _ _) <;> rfl
Lawful Functor Structure on Sum Types
Informal description
For any type $e$, the sum type $e \oplus \alpha$ forms a lawful functor, where the functor operations preserve the identity function and composition of functions.
Sum.instLawfulMonad_mathlib instance
: LawfulMonad (Sum.{v, u} e)
Full source
instance : LawfulMonad (Sum.{v, u} e) where
  seqRight_eq := by
    intros
    casesm Sum _ _ <;> casesm Sum _ _ <;> rfl
  seqLeft_eq := by
    intros
    casesm Sum _ _ <;> rfl
  pure_seq := by
    intros
    rfl
  bind_assoc := by
    intros
    casesm Sum _ _ <;> rfl
  pure_bind := by
    intros
    rfl
  bind_pure_comp := by
    intros
    casesm Sum _ _ <;> rfl
  bind_map := by
    intros
    casesm Sum _ _ <;> rfl
Lawful Monad Structure on Sum Types
Informal description
For any type $e$, the sum type $e \oplus \alpha$ forms a lawful monad, where the monadic operations satisfy the monad laws (left identity, right identity, and associativity) in addition to the functor laws.
CommApplicative structure
(m : Type u → Type v) [Applicative m] : Prop extends LawfulApplicative m
Full source
/-- A `CommApplicative` functor `m` is a (lawful) applicative functor which behaves identically on
`α × β` and `β × α`, so computations can occur in either order. -/
class CommApplicative (m : Type u → Type v) [Applicative m] : Prop extends LawfulApplicative m where
  /-- Computations performed first on `a : α` and then on `b : β` are equal to those performed in
  the reverse order. -/
  commutative_prod : ∀ {α β} (a : m α) (b : m β),
    Prod.mkProd.mk <$> aProd.mk <$> a <*> b = (fun (b : β) a => (a, b)) <$> b(fun (b : β) a => (a, b)) <$> b <*> a
Commutative Applicative Functor
Informal description
A commutative applicative functor `m` is a lawful applicative functor where the order of computations does not affect the result, i.e., for any types `α`, `β`, and `γ`, and any function `f : α → β → γ`, applying `f` to computations `a : m α` and `b : m β` in either order yields the same result.
CommApplicative.commutative_map theorem
{m : Type u → Type v} [h : Applicative m] [CommApplicative m] {α β γ} (a : m α) (b : m β) {f : α → β → γ} : f <$> a <*> b = flip f <$> b <*> a
Full source
theorem CommApplicative.commutative_map {m : Type u → Type v} [h : Applicative m]
    [CommApplicative m] {α β γ} (a : m α) (b : m β) {f : α → β → γ} :
  f <$> af <$> a <*> b = flipflip f <$> bflip f <$> b <*> a :=
  calc
    f <$> af <$> a <*> b = (fun p : α × β => f p.1 p.2) <$> (Prod.mk <$> a <*> b) := by
      simp only [map_seq, map_map, Function.comp_def]
    _ = (fun b a => f a b) <$> b(fun b a => f a b) <$> b <*> a := by
      rw [@CommApplicative.commutative_prod m h]
      simp [seq_map_assoc, map_seq, seq_assoc, seq_pure, map_map, (· ∘ ·)]
      rfl
Commutativity of Map and Sequential Application in Commutative Applicative Functors
Informal description
For any commutative applicative functor $m$, any types $\alpha$, $\beta$, and $\gamma$, and any function $f : \alpha \to \beta \to \gamma$, the following equality holds for all $a : m \alpha$ and $b : m \beta$: $$ f \text{ <\$> } a \text{ <*> } b = \text{flip } f \text{ <\$> } b \text{ <*> } a $$ where `<$>` denotes the `map` operation, `<*>` denotes the sequential application operation, and `flip` swaps the arguments of $f$.