Documentation

Init.Data.List.Monadic

Lemmas about List.mapM and List.forM. #

Monadic operations #

mapM #

def List.mapM' {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] (f : α → m β) :
List α → m (List β)

Alternate (non-tail-recursive) form of mapM for proofs.

Note that we can not have this as the main definition and replace it using a @[csimp] lemma, because they are only equal when m is a LawfulMonad.

Equations
Instances For
    @[simp]
    theorem List.mapM'_nil {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] {f : α → m β} :
    @[simp]
    theorem List.mapM'_cons {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} {a : α} {l : List α} [Monad m] {f : α → m β} :
    mapM' f (a :: l) = do let __do_lift ← f a let __do_lift_1 ← mapM' f l pure (__do_lift :: __do_lift_1)
    theorem List.mapM'_eq_mapM {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (f : α → m β) (l : List α) :
    mapM' f l = mapM f l
    theorem List.mapM'_eq_mapM.go {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (f : α → m β) (l : List α) (acc : List β) :
    mapM.loop f l acc = do let __do_lift ← mapM' f l pure (acc.reverse ++ __do_lift)
    @[simp]
    theorem List.mapM_nil {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] (f : α → m β) :
    @[simp]
    theorem List.mapM_cons {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} {a : α} {l : List α} [Monad m] [LawfulMonad m] (f : α → m β) :
    mapM f (a :: l) = do let __do_lift ← f a let __do_lift_1 ← mapM f l pure (__do_lift :: __do_lift_1)
    @[simp]
    theorem List.mapM_id {α : Type u_1} {β : Type u_2} {l : List α} {f : α → Id β} :
    mapM f l = map f l
    @[simp]
    theorem List.mapM_append {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (f : α → m β) {l₁ l₂ : List α} :
    mapM f (l₁ ++ l₂) = do let __do_lift ← mapM f l₁ let __do_lift_1 ← mapM f l₂ pure (__do_lift ++ __do_lift_1)
    theorem List.foldlM_cons_eq_append {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (f : α → m β) (as : List α) (b : β) (bs : List β) :
    foldlM (fun (acc : List β) (a : α) => do let __do_lift ← f a pure (__do_lift :: acc)) (b :: bs) as = (fun (x : List β) => x ++ b :: bs) <$> foldlM (fun (acc : List β) (a : α) => do let __do_lift ← f a pure (__do_lift :: acc)) [] as

    Auxiliary lemma for mapM_eq_reverse_foldlM_cons.

    theorem List.mapM_eq_reverse_foldlM_cons {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (f : α → m β) (l : List α) :
    mapM f l = reverse <$> foldlM (fun (acc : List β) (a : α) => do let __do_lift ← f a pure (__do_lift :: acc)) [] l

    filterMapM #

    @[simp]
    theorem List.filterMapM_nil {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] (f : α → m (Option β)) :
    theorem List.filterMapM_loop_eq {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (f : α → m (Option β)) (l : List α) (acc : List β) :
    filterMapM.loop f l acc = (fun (x : List β) => acc.reverse ++ x) <$> filterMapM.loop f l []
    @[simp]
    theorem List.filterMapM_cons {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} {a : α} {l : List α} [Monad m] [LawfulMonad m] (f : α → m (Option β)) :
    filterMapM f (a :: l) = do let __do_lift ← f a match __do_lift with | none => filterMapM f l | some b => do let __do_lift ← filterMapM f l pure (b :: __do_lift)

    flatMapM #

    @[simp]
    theorem List.flatMapM_nil {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] (f : α → m (List β)) :
    theorem List.flatMapM_loop_eq {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (f : α → m (List β)) (l : List α) (acc : List (List β)) :
    flatMapM.loop f l acc = (fun (x : List β) => acc.reverse.flatten ++ x) <$> flatMapM.loop f l []
    @[simp]
    theorem List.flatMapM_cons {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} {a : α} {l : List α} [Monad m] [LawfulMonad m] (f : α → m (List β)) :
    flatMapM f (a :: l) = do let bs ← f a let __do_lift ← flatMapM f l pure (bs ++ __do_lift)

    foldlM and foldrM #

    theorem List.foldlM_map {m : Type u_1 → Type u_2} {β₁ : Type u_3} {β₂ : Type u_4} {α : Type u_1} [Monad m] (f : β₁ → β₂) (g : α → β₂ → m α) (l : List β₁) (init : α) :
    foldlM g init (map f l) = foldlM (fun (x : α) (y : β₁) => g x (f y)) init l
    theorem List.foldrM_map {m : Type u_1 → Type u_2} {β₁ : Type u_3} {β₂ : Type u_4} {α : Type u_1} [Monad m] [LawfulMonad m] (f : β₁ → β₂) (g : β₂ → α → m α) (l : List β₁) (init : α) :
    foldrM g init (map f l) = foldrM (fun (x : β₁) (y : α) => g (f x) y) init l
    theorem List.foldlM_filterMap {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_4} {γ : Type u_1} [Monad m] [LawfulMonad m] (f : α → Option β) (g : γ → β → m γ) (l : List α) (init : γ) :
    foldlM g init (filterMap f l) = foldlM (fun (x : γ) (y : α) => match f y with | some b => g x b | none => pure x) init l
    theorem List.foldrM_filterMap {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_4} {γ : Type u_1} [Monad m] [LawfulMonad m] (f : α → Option β) (g : β → γ → m γ) (l : List α) (init : γ) :
    foldrM g init (filterMap f l) = foldrM (fun (x : α) (y : γ) => match f x with | some b => g b y | none => pure y) init l
    theorem List.foldlM_filter {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (p : α → Bool) (g : β → α → m β) (l : List α) (init : β) :
    foldlM g init (filter p l) = foldlM (fun (x : β) (y : α) => if p y = true then g x y else pure x) init l
    theorem List.foldrM_filter {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (p : α → Bool) (g : α → β → m β) (l : List α) (init : β) :
    foldrM g init (filter p l) = foldrM (fun (x : α) (y : β) => if p x = true then g x y else pure y) init l
    @[simp]
    theorem List.foldlM_attachWith {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] (l : List α) {q : α → Prop} (H : ∀ (a : α), a ∈ l → q a) {f : β → { x : α // q x } → m β} {b : β} :
    foldlM f b (l.attachWith q H) = foldlM (fun (b : β) (x : { x : α // x ∈ l }) => match x with | ⟨a, h⟩ => f b ⟨a, ⋯⟩) b l.attach
    @[simp]
    theorem List.foldrM_attachWith {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (l : List α) {q : α → Prop} (H : ∀ (a : α), a ∈ l → q a) {f : { x : α // q x } → β → m β} {b : β} :
    foldrM f b (l.attachWith q H) = foldrM (fun (a : { x : α // x ∈ l }) (acc : β) => f ⟨a.val, ⋯⟩ acc) b l.attach

    forM #

    @[deprecated List.forM_nil (since := "2025-01-31")]
    theorem List.forM_nil' {m : Type u_1 → Type u_2} {α : Type u_3} {f : α → m PUnit} [Monad m] :
    @[deprecated List.forM_cons (since := "2025-01-31")]
    theorem List.forM_cons' {m : Type u_1 → Type u_2} {α✝ : Type u_3} {a : α✝} {as : List α✝} {f : α✝ → m PUnit} [Monad m] :
    (a :: as).forM f = do f a as.forM f
    @[simp]
    theorem List.forM_append {m : Type u_1 → Type u_2} {α : Type u_3} [Monad m] [LawfulMonad m] (l₁ l₂ : List α) (f : α → m PUnit) :
    forM (l₁ ++ l₂) f = do forM l₁ f forM l₂ f
    @[simp]
    theorem List.forM_map {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_4} [Monad m] [LawfulMonad m] (l : List α) (g : α → β) (f : β → m PUnit) :
    forM (map g l) f = forM l fun (a : α) => f (g a)

    forIn' #

    theorem List.forIn'_loop_congr {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} {xs : List α} [Monad m] {as bs : List α} {f : (a' : α) → a' ∈ as → β → m (ForInStep β)} {g : (a' : α) → a' ∈ bs → β → m (ForInStep β)} {b : β} (ha : ∃ (ys : List α), ys ++ xs = as) (hb : ∃ (ys : List α), ys ++ xs = bs) (h : ∀ (a : α) (m_1 : a ∈ as) (m' : a ∈ bs) (b : β), f a m_1 b = g a m' b) :
    forIn'.loop as f xs b ha = forIn'.loop bs g xs b hb
    @[simp]
    theorem List.forIn'_cons {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] {a : α} {as : List α} (f : (a' : α) → a' ∈ a :: as → β → m (ForInStep β)) (b : β) :
    forIn' (a :: as) b f = do let x ← f a ⋯ b match x with | ForInStep.done b => pure b | ForInStep.yield b => forIn' as b fun (a' : α) (m : a' ∈ as) (b : β) => f a' ⋯ b
    @[simp]
    theorem List.forIn_cons {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] (f : α → β → m (ForInStep β)) (a : α) (as : List α) (b : β) :
    forIn (a :: as) b f = do let x ← f a b match x with | ForInStep.done b => pure b | ForInStep.yield b => forIn as b f
    theorem List.forIn'_congr {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] {as bs : List α} (w : as = bs) {b b' : β} (hb : b = b') {f : (a' : α) → a' ∈ as → β → m (ForInStep β)} {g : (a' : α) → a' ∈ bs → β → m (ForInStep β)} (h : ∀ (a : α) (m_1 : a ∈ bs) (b : β), f a ⋯ b = g a m_1 b) :
    forIn' as b f = forIn' bs b' g
    theorem List.forIn'_eq_foldlM {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (l : List α) (f : (a : α) → a ∈ l → β → m (ForInStep β)) (init : β) :
    forIn' l init f = ForInStep.value <$> foldlM (fun (b : ForInStep β) (x : { x : α // x ∈ l }) => match x with | ⟨a, m_1⟩ => match b with | ForInStep.yield b => f a m_1 b | ForInStep.done b => pure (ForInStep.done b)) (ForInStep.yield init) l.attach

    We can express a for loop over a list as a fold, in which whenever we reach .done b we keep that value through the rest of the fold.

    @[simp]
    theorem List.forIn'_yield_eq_foldlM {m : Type u_1 → Type u_2} {α : Type u_3} {β γ : Type u_1} [Monad m] [LawfulMonad m] (l : List α) (f : (a : α) → a ∈ l → β → m γ) (g : (a : α) → a ∈ l → β → γ → β) (init : β) :
    (forIn' l init fun (a : α) (m_1 : a ∈ l) (b : β) => (fun (c : γ) => ForInStep.yield (g a m_1 b c)) <$> f a m_1 b) = foldlM (fun (b : β) (x : { x : α // x ∈ l }) => match x with | ⟨a, m_1⟩ => g a m_1 b <$> f a m_1 b) init l.attach

    We can express a for loop over a list which always yields as a fold.

    theorem List.forIn'_pure_yield_eq_foldl {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (l : List α) (f : (a : α) → a ∈ l → β → β) (init : β) :
    (forIn' l init fun (a : α) (m_1 : a ∈ l) (b : β) => pure (ForInStep.yield (f a m_1 b))) = pure (foldl (fun (b : β) (x : { x : α // x ∈ l }) => match x with | ⟨a, h⟩ => f a h b) init l.attach)
    @[simp]
    theorem List.forIn'_yield_eq_foldl {α : Type u_1} {β : Type u_2} (l : List α) (f : (a : α) → a ∈ l → β → β) (init : β) :
    (forIn' l init fun (a : α) (m : a ∈ l) (b : β) => ForInStep.yield (f a m b)) = foldl (fun (b : β) (x : { x : α // x ∈ l }) => match x with | ⟨a, h⟩ => f a h b) init l.attach
    @[simp]
    theorem List.forIn'_map {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_4} {γ : Type u_1} {init : γ} [Monad m] [LawfulMonad m] (l : List α) (g : α → β) (f : (b : β) → b ∈ map g l → γ → m (ForInStep γ)) :
    forIn' (map g l) init f = forIn' l init fun (a : α) (h : a ∈ l) (y : γ) => f (g a) ⋯ y
    theorem List.forIn_eq_foldlM {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (f : α → β → m (ForInStep β)) (init : β) (l : List α) :
    forIn l init f = ForInStep.value <$> foldlM (fun (b : ForInStep β) (a : α) => match b with | ForInStep.yield b => f a b | ForInStep.done b => pure (ForInStep.done b)) (ForInStep.yield init) l

    We can express a for loop over a list as a fold, in which whenever we reach .done b we keep that value through the rest of the fold.

    @[simp]
    theorem List.forIn_yield_eq_foldlM {m : Type u_1 → Type u_2} {α : Type u_3} {β γ : Type u_1} [Monad m] [LawfulMonad m] (l : List α) (f : α → β → m γ) (g : α → β → γ → β) (init : β) :
    (forIn l init fun (a : α) (b : β) => (fun (c : γ) => ForInStep.yield (g a b c)) <$> f a b) = foldlM (fun (b : β) (a : α) => g a b <$> f a b) init l

    We can express a for loop over a list which always yields as a fold.

    theorem List.forIn_pure_yield_eq_foldl {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (l : List α) (f : α → β → β) (init : β) :
    (forIn l init fun (a : α) (b : β) => pure (ForInStep.yield (f a b))) = pure (foldl (fun (b : β) (a : α) => f a b) init l)
    @[simp]
    theorem List.forIn_yield_eq_foldl {α : Type u_1} {β : Type u_2} (l : List α) (f : α → β → β) (init : β) :
    (forIn l init fun (a : α) (b : β) => ForInStep.yield (f a b)) = foldl (fun (b : β) (a : α) => f a b) init l
    @[simp]
    theorem List.forIn_map {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_4} {γ : Type u_1} {init : γ} [Monad m] [LawfulMonad m] (l : List α) (g : α → β) (f : β → γ → m (ForInStep γ)) :
    forIn (map g l) init f = forIn l init fun (a : α) (y : γ) => f (g a) y

    allM #

    theorem List.allM_eq_not_anyM_not {m : Type → Type u_1} {α : Type u_2} [Monad m] [LawfulMonad m] (p : α → m Bool) (as : List α) :
    allM p as = (fun (x : Bool) => !x) <$> anyM (fun (x : α) => (fun (x : Bool) => !x) <$> p x) as

    Recognizing higher order functions using a function that only depends on the value. #

    @[simp]
    theorem List.foldlM_subtype {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] {p : α → Prop} {l : List { x : α // p x }} {f : β → { x : α // p x } → m β} {g : β → α → m β} {x : β} (hf : ∀ (b : β) (x : α) (h : p x), f b ⟨x, h⟩ = g b x) :
    foldlM f x l = foldlM g x l.unattach

    This lemma identifies monadic folds over lists of subtypes, where the function only depends on the value, not the proposition, and simplifies these to the function directly taking the value.

    theorem List.foldlM_wfParam {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] (xs : List α) (f : β → α → m β) :
    (fun (init : β) => foldlM f init (wfParam xs)) = fun (init : β) => foldlM f init xs.attach.unattach
    theorem List.foldlM_unattach {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] (P : α → Prop) (xs : List (Subtype P)) (f : β → α → m β) :
    (fun (init : β) => foldlM f init xs.unattach) = fun (init : β) => foldlM (fun (b : β) (x : Subtype P) => match x with | ⟨x, h⟩ => binderNameHint b f (binderNameHint x (f b) (binderNameHint h () (f b (wfParam x))))) init xs
    @[simp]
    theorem List.foldrM_subtype {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] {p : α → Prop} {l : List { x : α // p x }} {f : { x : α // p x } → β → m β} {g : α → β → m β} {x : β} (hf : ∀ (x : α) (h : p x) (b : β), f ⟨x, h⟩ b = g x b) :
    foldrM f x l = foldrM g x l.unattach

    This lemma identifies monadic folds over lists of subtypes, where the function only depends on the value, not the proposition, and simplifies these to the function directly taking the value.

    theorem List.foldrM_wfParam {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (xs : List α) (f : α → β → m β) :
    (fun (init : β) => foldrM f init (wfParam xs)) = fun (init : β) => foldrM f init xs.attach.unattach
    theorem List.foldrM_unattach {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (P : α → Prop) (xs : List (Subtype P)) (f : α → β → m β) :
    (fun (init : β) => foldrM f init xs.unattach) = fun (init : β) => foldrM (fun (x : Subtype P) (b : β) => match x with | ⟨x, h⟩ => binderNameHint x f (binderNameHint h () (binderNameHint b (f x) (f (wfParam x) b)))) init xs
    @[simp]
    theorem List.mapM_subtype {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] {p : α → Prop} {l : List { x : α // p x }} {f : { x : α // p x } → m β} {g : α → m β} (hf : ∀ (x : α) (h : p x), f ⟨x, h⟩ = g x) :

    This lemma identifies monadic maps over lists of subtypes, where the function only depends on the value, not the proposition, and simplifies these to the function directly taking the value.

    theorem List.mapM_wfParam {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (xs : List α) (f : α → m β) :
    theorem List.mapM_unattach {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (P : α → Prop) (xs : List (Subtype P)) (f : α → m β) :
    mapM f xs.unattach = mapM (fun (x : Subtype P) => match x with | ⟨x, h⟩ => binderNameHint x f (binderNameHint h () (f (wfParam x)))) xs
    @[simp]
    theorem List.filterMapM_subtype {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] {p : α → Prop} {l : List { x : α // p x }} {f : { x : α // p x } → m (Option β)} {g : α → m (Option β)} (hf : ∀ (x : α) (h : p x), f ⟨x, h⟩ = g x) :
    theorem List.filterMapM_wfParam {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (xs : List α) (f : α → m (Option β)) :
    theorem List.filterMapM_unattach {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (P : α → Prop) (xs : List (Subtype P)) (f : α → m (Option β)) :
    filterMapM f xs.unattach = filterMapM (fun (x : Subtype P) => match x with | ⟨x, h⟩ => binderNameHint x f (binderNameHint h () (f (wfParam x)))) xs
    @[simp]
    theorem List.flatMapM_subtype {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] {p : α → Prop} {l : List { x : α // p x }} {f : { x : α // p x } → m (List β)} {g : α → m (List β)} (hf : ∀ (x : α) (h : p x), f ⟨x, h⟩ = g x) :
    theorem List.flatMapM_wfParam {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (xs : List α) (f : α → m (List β)) :
    theorem List.flatMapM_unattach {m : Type u_1 → Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] [LawfulMonad m] (P : α → Prop) (xs : List (Subtype P)) (f : α → m (List β)) :
    flatMapM f xs.unattach = flatMapM (fun (x : Subtype P) => match x with | ⟨x, h⟩ => binderNameHint x f (binderNameHint h () (f (wfParam x)))) xs