Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - feat: port Control.Basic #588

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ed6930b
Begin
ADedecker Nov 12, 2022
545f22f
Problem with `mapConstRev`
ADedecker Nov 12, 2022
b1227a3
Most done
ADedecker Nov 12, 2022
01bdbd0
Follow naming conventions for monads
ADedecker Nov 13, 2022
e3813a9
Add warnings back, rename
ADedecker Nov 13, 2022
41b1635
Fix
ADedecker Nov 13, 2022
331221b
fix module docstring
j-loreaux Nov 17, 2022
551bc46
remove unnecessary section and comment out notation
j-loreaux Nov 17, 2022
3409637
docstrings
j-loreaux Nov 17, 2022
582a4f5
`#align` with `ₓ` for dubious translations
j-loreaux Nov 17, 2022
12e8755
try to appease `check_univs` linter
j-loreaux Nov 17, 2022
cbe7c6c
remove notation `$<`
j-loreaux Nov 17, 2022
8fa98e8
remove dubious translation warnings
j-loreaux Nov 17, 2022
3974e7e
remove `fish` definition entirely
j-loreaux Nov 17, 2022
8ece2e0
fix `fish_assoc`
j-loreaux Nov 17, 2022
a89877c
fix > 100 chars
j-loreaux Nov 17, 2022
ee5dc23
add module docstring
j-loreaux Nov 17, 2022
87a1f01
fix indentation
j-loreaux Nov 17, 2022
d242aaf
appease checkUnivs linter
j-loreaux Nov 17, 2022
863c568
oops, remove lint imports
j-loreaux Nov 17, 2022
330726a
fix import order
j-loreaux Nov 17, 2022
2cbb935
Merge branch 'master' into AD_PORT_control_basic
Ruben-VandeVelde Nov 18, 2022
93fe56d
merge
kim-em Nov 20, 2022
d1b441e
typo
j-loreaux Nov 21, 2022
b3823ba
code review
j-loreaux Nov 22, 2022
a20f7a6
Merge remote-tracking branch 'origin/master' into AD_PORT_control_basic
Ruben-VandeVelde Nov 22, 2022
2492cc0
Merge branch 'master' into AD_PORT_control_basic
j-loreaux Nov 23, 2022
7e3f878
code review
j-loreaux Nov 23, 2022
4a01937
Merge branch 'master' into AD_PORT_control_basic
j-loreaux Nov 24, 2022
497a3b8
code review
j-loreaux Nov 24, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Mathlib.lean
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ import Mathlib.Algebra.Ring.Basic
import Mathlib.Algebra.Ring.Defs
import Mathlib.Algebra.Ring.OrderSynonym
import Mathlib.CategoryTheory.ConcreteCategory.Bundled
import Mathlib.Control.Basic
import Mathlib.Control.EquivFunctor
import Mathlib.Control.Random
import Mathlib.Control.SimpSet
import Mathlib.Control.ULift
import Mathlib.Control.Writer
import Mathlib.Data.Array.Basic
Expand Down
269 changes: 269 additions & 0 deletions Mathlib/Control/Basic.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
/-
Copyright (c) 2017 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl
-/
import Mathlib.Control.SimpSet
import Mathlib.Tactic.CasesM
import Mathlib.Init.Control.Combinators

/-!
Extends the theory on functors, applicatives and monads.
-/

universe u v w

variable {α β γ : Type u}

section Functor

variable {f : Type u → Type v} [Functor f] [LawfulFunctor f]
@[functor_norm]
theorem Functor.map_map (m : α → β) (g : β → γ) (x : f α) : g <$> m <$> x = (g ∘ m) <$> x :=
(comp_map _ _ _).symm
#align functor.map_map Functor.map_mapₓ
j-loreaux marked this conversation as resolved.
Show resolved Hide resolved
-- order of implicits

attribute [simp] id_map'
#align id_map' id_map'ₓ
j-loreaux marked this conversation as resolved.
Show resolved Hide resolved
-- order of implicits

end Functor

section Applicative

variable {F : Type u → Type v} [Applicative F]

/-- A generalization of `List.zipWith` which combines list elements with an `Applicative`. -/
def zipMWith {α₁ α₂ φ : Type u} (f : α₁ → α₂ → F φ) : ∀ (_ : List α₁) (_ : List α₂), F (List φ)
j-loreaux marked this conversation as resolved.
Show resolved Hide resolved
| x :: xs, y :: ys => (· :: ·) <$> f x y <*> zipMWith f xs ys
| _, _ => pure []
#align mzip_with zipMWith

/-- Like `zipMWith` but evaluates the result as it traverses the lists using `*>`. -/
def zipMWith' (f : α → β → F γ) : List α → List β → F PUnit
| x :: xs, y :: ys => f x y *> zipMWith' f xs ys
| [], _ => pure PUnit.unit
| _, [] => pure PUnit.unit
#align mzip_with' zipMWith'

variable [LawfulApplicative F]

attribute [functor_norm] seq_assoc pure_seq

@[simp]
theorem pure_id'_seq (x : F α) : (pure fun x => x) <*> x = x :=
pure_id_seq x
#align pure_id'_seq pure_id'_seq

attribute [functor_norm] seq_assoc pure_seq

@[functor_norm]
theorem seq_map_assoc (x : F (α → β)) (f : γ → α) (y : F γ) :
x <*> f <$> y = (· ∘ f) <$> x <*> y := by
simp [← pure_seq]
simp [seq_assoc, ← comp_map, (· ∘ ·)]
simp [pure_seq]
#align seq_map_assoc seq_map_assoc

@[functor_norm]
theorem map_seq (f : β → γ) (x : F (α → β)) (y : F α) :
f <$> (x <*> y) = (f ∘ ·) <$> x <*> y := by
simp only [← pure_seq]; simp [seq_assoc]
#align map_seq map_seq

end Applicative

-- TODO: setup `functor_norm` for `monad` laws
attribute [functor_norm] pure_bind bind_assoc bind_pure

section Monad

variable {m : Type u → Type v} [Monad m] [LawfulMonad m]

open List

/-- A generalization of `List.partition` which partitions the list according to a monadic
predicate. `List.partition` corresponds to the case where `f = Id`. -/
def List.partitionM {f : Type → Type} [Monad f] {α : Type} (p : α → f Bool) :
List α → f (List α × List α)
| [] => pure ([], [])
| x :: xs => condM (p x)
(Prod.map (cons x) id <$> List.partitionM p xs)
(Prod.map id (cons x) <$> List.partitionM p xs)
#align list.mpartition List.partitionM

theorem map_bind (x : m α) {g : α → m β} {f : β → γ} :
f <$> (x >>= g) = x >>= fun a => f <$> g a := by
rw [← bind_pure_comp, bind_assoc] <;> simp [bind_pure_comp]
#align map_bind map_bind

theorem seq_bind_eq (x : m α) {g : β → m γ} {f : α → β} :
f <$> x >>= g = x >>= g ∘ f :=
show bind (f <$> x) g = bind x (g ∘ f)
by rw [← bind_pure_comp, bind_assoc] <;> simp [pure_bind, (· ∘ ·)]
#align seq_bind_eq seq_bind_eq

#align seq_eq_bind_map seq_eq_bind_mapₓ
j-loreaux marked this conversation as resolved.
Show resolved Hide resolved
-- order of implicits and `Seq.seq` has a lazily evaluated second argument using `Unit`

@[functor_norm]
theorem fish_pure {α β} (f : α → m β) : f >=> pure = f := by simp only [(· >=> ·), functor_norm]
#align fish_pure fish_pure

@[functor_norm]
theorem fish_pipe {α β} (f : α → m β) : pure >=> f = f := by simp only [(· >=> ·), functor_norm]
#align fish_pipe fish_pipe

-- note: in Lean 3 `>=>` is left-associative, but in Lean 4 it is right-associative.
@[functor_norm]
theorem fish_assoc {α β γ φ} (f : α → m β) (g : β → m γ) (h : γ → m φ) :
(f >=> g) >=> h = f >=> g >=> h := by
simp only [(· >=> ·), functor_norm]
#align fish_assoc fish_assoc

variable {β' γ' : Type v}

variable {m' : Type v → Type w} [Monad m']

/-- 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.mapMAccumR (f : α → β' → m' (β' × γ')) : β' → List α → m' (β' × List γ')
j-loreaux marked this conversation as resolved.
Show resolved Hide resolved
| a, [] => pure (a, [])
| a, x :: xs => do
let (a', ys) ← List.mapMAccumR f a xs
let (a'', y) ← f x a'
pure (a'', y :: ys)
#align list.mmap_accumr List.mapMAccumR

/-- 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.mapMAccumL (f : β' → α → m' (β' × γ')) : β' → List α → m' (β' × List γ')
| a, [] => pure (a, [])
| a, x :: xs => do
let (a', y) ← f a x
let (a'', ys) ← List.mapMAccumL f a' xs
pure (a'', y :: ys)
#align list.mmap_accuml List.mapMAccumL

end Monad

section

variable {m : Type u → Type u} [Monad m] [LawfulMonad m]

theorem joinM_map_map {α β : Type u} (f : α → β) (a : m (m α)) :
joinM (Functor.map f <$> a) = f <$> joinM a := by
simp only [joinM, (· ∘ ·), id.def, ← bind_pure_comp, bind_assoc, map_bind, pure_bind]
#align mjoin_map_map joinM_map_map

theorem joinM_map_joinM {α : Type u} (a : m (m (m α))) : joinM (joinM <$> a) = joinM (joinM a) := by
simp only [joinM, (· ∘ ·), id.def, map_bind, ← bind_pure_comp, bind_assoc, pure_bind]
#align mjoin_map_mjoin joinM_map_joinM

@[simp]
theorem joinM_map_pure {α : Type u} (a : m α) : joinM (pure <$> a) = a := by
simp only [joinM, (· ∘ ·), id.def, map_bind, ← bind_pure_comp, bind_assoc, pure_bind, bind_pure]
#align mjoin_map_pure joinM_map_pure

@[simp]
theorem joinM_pure {α : Type u} (a : m α) : joinM (pure a) = a :=
LawfulMonad.pure_bind a id
#align mjoin_pure joinM_pure

end

section Alternative

variable {F : Type → Type v} [Alternative F]

-- [todo] add notation for `Functor.mapConst` and port `functor.map_const_rev`
kim-em marked this conversation as resolved.
Show resolved Hide resolved
/-- Returns `pure true` if the computation succeeds and `pure false` otherwise. -/
def succeeds {α} (x : F α) : F Bool :=
Functor.mapConst true x <|> pure false
#align succeeds succeeds

/-- Attempts to perform the computation, but fails silently if it doesn't succeed. -/
def tryM {α} (x : F α) : F Unit :=
Functor.mapConst () x <|> pure ()
#align mtry tryM

@[simp]
theorem guard_true {h : Decidable True} : @guard F _ True h = pure () := by simp [guard, if_pos]
#align guard_true guard_true

@[simp]
theorem guard_false {h : Decidable False} : @guard F _ False h = failure :=
by simp [guard, if_neg not_false]
#align guard_false guard_false

end Alternative

namespace Sum

variable {e : Type v}

/-- The monadic `bind` operation for `Sum`. -/
protected def bind {α β} : Sum e α → (α → Sum e β) → Sum e β
| inl x, _ => inl x
| inr x, f => f x
#align sum.bind Sum.bindₓ
j-loreaux marked this conversation as resolved.
Show resolved Hide resolved
-- incorrectly marked as a bad translation by mathport
j-loreaux marked this conversation as resolved.
Show resolved Hide resolved

instance : Monad (Sum.{v, u} e) where
pure := @Sum.inr e
bind := @Sum.bind e

instance : LawfulFunctor (Sum.{v, u} e) := by refine' { .. } <;> intros <;> casesm Sum _ _ <;> rfl

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

end Sum

/-- 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] extends LawfulApplicative m : Prop 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.mk <$> a <*> b = (fun (b : β) a => (a, b)) <$> b <*> a
#align is_comm_applicative CommApplicative

open Functor

variable {m}

theorem CommApplicative.commutative_map {m : Type u → Type v} [h : Applicative m]
[CommApplicative m] {α β γ} (a : m α) (b : m β) {f : α → β → γ} :
f <$> a <*> b = flip f <$> b <*> a :=
calc
f <$> a <*> b = (fun p : α × β => f p.1 p.2) <$> (Prod.mk <$> a <*> b) :=
by
simp [seq_map_assoc, map_seq, seq_assoc, seq_pure, map_map] <;> rfl
_ = (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, (· ∘ ·)]

#align is_comm_applicative.commutative_map CommApplicative.commutative_map
12 changes: 12 additions & 0 deletions Mathlib/Control/SimpSet.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/-
Copyright (c) 2022 Anatole Dedecker. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Anatole Dedecker
-/

import Lean.Meta.Tactic.Simp

/-! Simp set for `functor_norm` -/

/-- Simp set for `functor_norm` -/
register_simp_attr functor_norm
7 changes: 2 additions & 5 deletions Mathlib/Data/Equiv/Functor.lean
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ Copyright (c) 2019 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin, Simon Hudon, Scott Morrison
-/

import Mathlib.Control.Basic
import Mathlib.Logic.Equiv.Defs

/-!
Expand All @@ -22,11 +24,6 @@ namespace Functor

variable (f : Type u → Type v) [Functor f] [LawfulFunctor f]

-- this is in control.basic in Lean 3
theorem map_map (m : α → β) (g : β → γ) (x : f α) :
g <$> (m <$> x) = (g ∘ m) <$> x :=
(comp_map _ _ _).symm

/-- Apply a functor to an `equiv`. -/
def map_equiv (h : α ≃ β) : f α ≃ f β where
toFun := map h
Expand Down