Reason: it contains a bunch of little functions that are supposed to be defined in other modules.
121 lines
4.7 KiB
Text
121 lines
4.7 KiB
Text
/-
|
||
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Author: Leonardo de Moura
|
||
-/
|
||
prelude
|
||
import Init.Control.Monad
|
||
import Init.Control.Alternative
|
||
|
||
namespace List
|
||
universes u v w u₁ u₂
|
||
|
||
/-
|
||
Remark: we can define `mapM`, `mapM₂` and `forM` using `Applicative` instead of `Monad`.
|
||
Example:
|
||
```
|
||
def mapM {m : Type u → Type v} [Applicative m] {α : Type w} {β : Type u} (f : α → m β) : List α → m (List β)
|
||
| [] => pure []
|
||
| a::as => List.cons <$> (f a) <*> mapM as
|
||
```
|
||
|
||
However, we consider `f <$> a <*> b` an anti-idiom because the generated code
|
||
may produce unnecessary closure allocations.
|
||
Suppose `m` is a `Monad`, and it uses the default implementation for `Applicative.seq`.
|
||
Then, the compiler expands `f <$> a <*> b <*> c` into something equivalent to
|
||
```
|
||
(Functor.map f a >>= fun g_1 => Functor.map g_1 b) >>= fun g_2 => Functor.map g_2 c
|
||
```
|
||
In an ideal world, the compiler may eliminate the temporary closures `g_1` and `g_2` after it inlines
|
||
`Functor.map` and `Monad.bind`. However, this can easily fail. For example, suppose
|
||
`Functor.map f a >>= fun g_1 => Functor.map g_1 b` expanded into a match-expression.
|
||
This is not unreasonable and can happen in many different ways, e.g., we are using a monad that
|
||
may throw exceptions. Then, the compiler has to decide whether it will create a join-point for
|
||
the continuation of the match or float it. If the compiler decides to float, then it will
|
||
be able to eliminate the closures, but it may not be feasible since floating match expressions
|
||
may produce exponential blowup in the code size.
|
||
|
||
Finally, we rarely use `mapM` with something that is not a `Monad`.
|
||
|
||
Users that want to use `mapM` with `Applicative` should use `mapA` instead.
|
||
-/
|
||
|
||
@[specialize]
|
||
def mapM {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f : α → m β) : List α → m (List β)
|
||
| [] => pure []
|
||
| a::as => do b ← f a; bs ← mapM as; pure (b :: bs)
|
||
|
||
@[specialize]
|
||
def mapM₂ {m : Type u → Type v} [Monad m] {α : Type u₁} {β : Type u₂} {γ : Type u} (f : α → β → m γ) : List α → List β → m (List γ)
|
||
| a::as, b::bs => do c ← f a b; cs ← mapM₂ as bs; pure (c :: cs)
|
||
| _, _ => pure []
|
||
|
||
@[specialize]
|
||
def mapA {m : Type u → Type v} [Applicative m] {α : Type w} {β : Type u} (f : α → m β) : List α → m (List β)
|
||
| [] => pure []
|
||
| a::as => List.cons <$> f a <*> mapA as
|
||
|
||
@[specialize]
|
||
def mapA₂ {m : Type u → Type v} [Applicative m] {α : Type u₁} {β : Type u₂} {γ : Type u} (f : α → β → m γ) : List α → List β → m (List γ)
|
||
| a::as, b::bs => List.cons <$> f a b <*> mapA₂ as bs
|
||
| _, _ => pure []
|
||
|
||
@[specialize]
|
||
def forM {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f : α → m β) : List α → m PUnit
|
||
| [] => pure ⟨⟩
|
||
| h :: t => do f h; forM t
|
||
|
||
@[specialize]
|
||
def forM₂ {m : Type u → Type v} [Monad m] {α : Type u₁} {β : Type u₂} {γ : Type u} (f : α → β → m γ) : List α → List β → m PUnit
|
||
| a::as, b::bs => do f a b; forM₂ as bs
|
||
| _, _ => pure ⟨⟩
|
||
|
||
@[specialize]
|
||
def forA {m : Type u → Type v} [Applicative m] {α : Type w} {β : Type u} (f : α → m β) : List α → m PUnit
|
||
| [] => pure ⟨⟩
|
||
| h :: t => f h *> forA t
|
||
|
||
@[specialize]
|
||
def forA₂ {m : Type u → Type v} [Applicative m] {α : Type u₁} {β : Type u₂} {γ : Type u} (f : α → β → m γ) : List α → List β → m PUnit
|
||
| a::as, b::bs => f a b *> forA₂ as bs
|
||
| _, _ => pure ⟨⟩
|
||
|
||
@[specialize]
|
||
def filterM {m : Type → Type v} [Monad m] {α : Type} (f : α → m Bool) : List α → m (List α)
|
||
| [] => pure []
|
||
| h :: t => do b ← f h; t' ← filterM t; cond b (pure (h :: t')) (pure t')
|
||
|
||
@[specialize]
|
||
def foldlM {m : Type u → Type v} [Monad m] {s : Type u} {α : Type w} : (s → α → m s) → s → List α → m s
|
||
| f, s, [] => pure s
|
||
| f, s, h :: r => do
|
||
s' ← f s h;
|
||
foldlM f s' r
|
||
|
||
@[specialize]
|
||
def foldrM {m : Type u → Type v} [Monad m] {s : Type u} {α : Type w} : (α → s → m s) → s → List α → m s
|
||
| f, s, [] => pure s
|
||
| f, s, h :: r => do
|
||
s' ← foldrM f s r;
|
||
f h s'
|
||
|
||
@[specialize]
|
||
def firstM {m : Type u → Type v} [Monad m] [Alternative m] {α : Type w} {β : Type u} (f : α → m β) : List α → m β
|
||
| [] => failure
|
||
| a::as => f a <|> firstM as
|
||
|
||
@[specialize]
|
||
def anyM {m : Type → Type u} [Monad m] {α : Type v} (f : α → m Bool) : List α → m Bool
|
||
| [] => pure false
|
||
| a::as => do b ← f a; match b with
|
||
| true => pure true
|
||
| false => anyM as
|
||
|
||
@[specialize]
|
||
def allM {m : Type → Type u} [Monad m] {α : Type v} (f : α → m Bool) : List α → m Bool
|
||
| [] => pure true
|
||
| a::as => do b ← f a; match b with
|
||
| true => allM as
|
||
| false => pure false
|
||
|
||
end List
|