doc: docstring review for monads and transformers (#7548)

This PR adds missing monad transformer docstrings and makes their style
consistent.

---------

Co-authored-by: Bhavik Mehta <bm489@cam.ac.uk>
This commit is contained in:
David Thrane Christiansen 2025-03-20 13:18:46 +01:00 committed by GitHub
parent edbb84d23b
commit d8cbf1cefc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 521 additions and 140 deletions

View file

@ -270,21 +270,61 @@ Using `control` means that `runInBase` can be used multiple times.
-/
/-- MonadControl is a way of stating that the monad `m` can be 'run inside' the monad `n`.
This is the same as [`MonadBaseControl`](https://hackage.haskell.org/package/monad-control-1.0.3.1/docs/Control-Monad-Trans-Control.html#t:MonadBaseControl) in Haskell.
To learn about `MonadControl`, see the comment above this docstring.
/--
A way to lift a computation from one monad to another while providing the lifted computation with a
means of interpreting computations from the outer monad. This provides a means of lifting
higher-order operations automatically.
Clients should typically use `control` or `controlAt`, which request an instance of `MonadControlT`:
the reflexive, transitive closure of `MonadControl`. New instances should be defined for
`MonadControl` itself.
-/
-- This is the same as
-- [`MonadBaseControl`](https://hackage.haskell.org/package/monad-control-1.0.3.1/docs/Control-Monad-Trans-Control.html#t:MonadBaseControl)
-- in Haskell.
class MonadControl (m : semiOutParam (Type u → Type v)) (n : Type u → Type w) where
/--
A type that can be used to reconstruct both a returned value and any state used by the outer
monad.
-/
stM : Type u → Type u
/--
Lifts an action from the inner monad `m` to the outer monad `n`. The inner monad has access to a
reverse lifting operator that can run an `n` action, returning a value and state together.
-/
liftWith : {α : Type u} → (({β : Type u} → n β → m (stM β)) → m α) → n α
/--
Lifts a monadic action that returns a state and a value in the inner monad to an action in the
outer monad. The extra state information is used to restore the results of effects from the
reverse lift passed to `liftWith`'s parameter.
-/
restoreM : {α : Type u} → m (stM α) → n α
/-- Transitive closure of MonadControl. -/
/--
A way to lift a computation from one monad to another while providing the lifted computation with a
means of interpreting computations from the outer monad. This provides a means of lifting
higher-order operations automatically.
Clients should typically use `control` or `controlAt`, which request an instance of `MonadControlT`:
the reflexive, transitive closure of `MonadControl`. New instances should be defined for
`MonadControl` itself.
-/
class MonadControlT (m : Type u → Type v) (n : Type u → Type w) where
/--
A type that can be used to reconstruct both a returned value and any state used by the outer
monad.
-/
stM : Type u → Type u
/--
Lifts an action from the inner monad `m` to the outer monad `n`. The inner monad has access to a
reverse lifting operator that can run an `n` action, returning a value and state together.
-/
liftWith : {α : Type u} → (({β : Type u} → n β → m (stM β)) → m α) → n α
/--
Lifts a monadic action that returns a state and a value in the inner monad to an action in the
outer monad. The extra state information is used to restore the results of effects from the
reverse lift passed to `liftWith`'s parameter.
-/
restoreM {α : Type u} : stM α → n α
export MonadControlT (stM liftWith restoreM)
@ -300,11 +340,28 @@ instance (m : Type u → Type v) [Pure m] : MonadControlT m m where
liftWith f := f fun x => x
restoreM x := pure x
/--
Lifts an operation from an inner monad to an outer monad, providing it with a reverse lifting
operator that allows outer monad computations to be run in the inner monad. The lifted operation is
required to return extra information that is required in order to reconstruct the reverse lift's
effects in the outer monad; this extra information is determined by `stM`.
This function takes the inner monad as an explicit parameter. Use `control` to infer the monad.
-/
@[always_inline, inline]
def controlAt (m : Type u → Type v) {n : Type u → Type w} [MonadControlT m n] [Bind n] {α : Type u}
(f : ({β : Type u} → n β → m (stM m n β)) → m (stM m n α)) : n α :=
liftWith f >>= restoreM
/--
Lifts an operation from an inner monad to an outer monad, providing it with a reverse lifting
operator that allows outer monad computations to be run in the inner monad. The lifted operation is
required to return extra information that is required in order to reconstruct the reverse lift's
effects in the outer monad; this extra information is determined by `stM`.
This function takes the inner monad as an implicit parameter. Use `controlAt` to specify it
explicitly.
-/
@[always_inline, inline]
def control {m : Type u → Type v} {n : Type u → Type w} [MonadControlT m n] [Bind n] {α : Type u}
(f : ({β : Type u} → n β → m (stM m n β)) → m (stM m n α)) : n α :=

View file

@ -8,13 +8,22 @@ import Init.Data.Option.Basic
import Init.Control.Basic
import Init.Control.Except
set_option linter.missingDocs true
universe u v
instance : ToBool (Option α) := ⟨Option.isSome⟩
/--
Adds the ability to fail to a monad. Unlike ordinary exceptions, there is no way to signal why a
failure occurred.
-/
def OptionT (m : Type u → Type v) (α : Type u) : Type v :=
m (Option α)
/--
Executes an action that might fail in the underlying monad `m`, returning `none` in case of failure.
-/
@[always_inline, inline]
def OptionT.run {m : Type u → Type v} {α : Type u} (x : OptionT m α) : m (Option α) :=
x
@ -22,15 +31,25 @@ def OptionT.run {m : Type u → Type v} {α : Type u} (x : OptionT m α) : m (Op
namespace OptionT
variable {m : Type u → Type v} [Monad m] {α β : Type u}
/--
Converts an action that returns an `Option` into one that might fail, with `none` indicating
failure.
-/
protected def mk (x : m (Option α)) : OptionT m α :=
x
/--
Sequences two potentially-failing actions. The second action is run only if the first succeeds.
-/
@[always_inline, inline]
protected def bind (x : OptionT m α) (f : α → OptionT m β) : OptionT m β := OptionT.mk do
match (← x) with
| some a => f a
| none => pure none
/--
Succeeds with the provided value.
-/
@[always_inline, inline]
protected def pure (a : α) : OptionT m α := OptionT.mk do
pure (some a)
@ -40,11 +59,17 @@ instance : Monad (OptionT m) where
pure := OptionT.pure
bind := OptionT.bind
/--
Recovers from failures. Typically used via the `<|>` operator.
-/
@[always_inline, inline] protected def orElse (x : OptionT m α) (y : Unit → OptionT m α) : OptionT m α := OptionT.mk do
match (← x) with
| some a => pure (some a)
| _ => y ()
/--
A recoverable failure.
-/
@[always_inline, inline] protected def fail : OptionT m α := OptionT.mk do
pure none
@ -52,6 +77,12 @@ instance : Alternative (OptionT m) where
failure := OptionT.fail
orElse := OptionT.orElse
/--
Converts a computation from the underlying monad into one that could fail, even though it does not.
This function is typically implicitly accessed via a `MonadLiftT` instance as part of [automatic
lifting](lean-manual://section/monad-lifting).
-/
@[always_inline, inline] protected def lift (x : m α) : OptionT m α := OptionT.mk do
return some (← x)
@ -59,6 +90,9 @@ instance : MonadLift m (OptionT m) := ⟨OptionT.lift⟩
instance : MonadFunctor m (OptionT m) := ⟨fun f x => f x⟩
/--
Handles failures by treating them as exceptions of type `Unit`.
-/
@[always_inline, inline] protected def tryCatch (x : OptionT m α) (handle : Unit → OptionT m α) : OptionT m α := OptionT.mk do
let some a ← x | handle ()
pure a

View file

@ -10,12 +10,21 @@ import Init.Control.Basic
import Init.Control.Id
import Init.Control.Except
set_option linter.missingDocs true
namespace ReaderT
/--
Recovers from errors. The same local value is provided to both branches. Typically used via the
`<|>` operator.
-/
@[always_inline, inline]
protected def orElse [Alternative m] (x₁ : ReaderT ρ m α) (x₂ : Unit → ReaderT ρ m α) : ReaderT ρ m α :=
fun s => x₁ s <|> x₂ () s
/--
Fails with a recoverable error.
-/
@[always_inline, inline]
protected def failure [Alternative m] : ReaderT ρ m α :=
fun _ => failure
@ -35,4 +44,8 @@ instance : MonadControl m (ReaderT ρ m) where
instance ReaderT.tryFinally [MonadFinally m] : MonadFinally (ReaderT ρ m) where
tryFinally' x h ctx := tryFinally' (x ctx) (fun a? => h a? ctx)
/--
A monad with access to a read-only value of type `ρ`. The value can be locally overridden by
`withReader`, but it cannot be mutated.
-/
@[reducible] def ReaderM (ρ : Type u) := ReaderT ρ Id

View file

@ -9,19 +9,42 @@ prelude
import Init.Control.Basic
import Init.Control.Id
import Init.Control.Except
set_option linter.missingDocs true
universe u v w
/--
Adds a mutable state of type `σ` to a monad.
Actions in the resulting monad are functions that take an initial state and return, in `m`, a tuple
of a value and a state.
-/
def StateT (σ : Type u) (m : Type u → Type v) (α : Type u) : Type (max u v) :=
σ → m (α × σ)
/--
Executes an action from a monad with added state in the underlying monad `m`. Given an initial
state, it returns a value paired with the final state.
-/
@[always_inline, inline]
def StateT.run {σ : Type u} {m : Type u → Type v} {α : Type u} (x : StateT σ m α) (s : σ) : m (α × σ) :=
x s
/--
Executes an action from a monad with added state in the underlying monad `m`. Given an initial
state, it returns a value, discarding the final state.
-/
@[always_inline, inline]
def StateT.run' {σ : Type u} {m : Type u → Type v} [Functor m] {α : Type u} (x : StateT σ m α) (s : σ) : m α :=
(·.1) <$> x s
/--
A tuple-based state monad.
Actions in `StateM σ` are functions that take an initial state and return a value paired with a
final state.
-/
@[reducible]
def StateM (σ α : Type u) : Type u := StateT σ Id α
@ -38,14 +61,23 @@ section
variable {σ : Type u} {m : Type u → Type v}
variable [Monad m] {α β : Type u}
/--
Returns the given value without modifying the state. Typically used via `Pure.pure`.
-/
@[always_inline, inline]
protected def pure (a : α) : StateT σ m α :=
fun s => pure (a, s)
/--
Sequences two actions. Typically used via the `>>=` operator.
-/
@[always_inline, inline]
protected def bind (x : StateT σ m α) (f : α → StateT σ m β) : StateT σ m β :=
fun s => do let (a, s) ← x s; f a s
/--
Modifies the value returned by a computation. Typically used via the `<$>` operator.
-/
@[always_inline, inline]
protected def map (f : α → β) (x : StateT σ m α) : StateT σ m β :=
fun s => do let (a, s) ← x s; pure (f a, s)
@ -56,10 +88,17 @@ instance : Monad (StateT σ m) where
bind := StateT.bind
map := StateT.map
/--
Recovers from errors. The state is rolled back on error recovery. Typically used via the `<|>`
operator.
-/
@[always_inline, inline]
protected def orElse [Alternative m] {α : Type u} (x₁ : StateT σ m α) (x₂ : Unit → StateT σ m α) : StateT σ m α :=
fun s => x₁ s <|> x₂ () s
/--
Fails with a recoverable error. The state is rolled back on error recovery.
-/
@[always_inline, inline]
protected def failure [Alternative m] {α : Type u} : StateT σ m α :=
fun _ => failure
@ -68,18 +107,40 @@ instance [Alternative m] : Alternative (StateT σ m) where
failure := StateT.failure
orElse := StateT.orElse
/--
Retrieves the current value of the monad's mutable state.
This increments the reference count of the state, which may inhibit in-place updates.
-/
@[always_inline, inline]
protected def get : StateT σ m σ :=
fun s => pure (s, s)
/--
Replaces the mutable state with a new value.
-/
@[always_inline, inline]
protected def set : σ → StateT σ m PUnit :=
fun s' _ => pure (⟨⟩, s')
/--
Applies a function to the current state that both computes a new state and a value. The new state
replaces the current state, and the value is returned.
It is equivalent to `do let (a, s) := f (← StateT.get); StateT.set s; pure a`. However, using
`StateT.modifyGet` may lead to better performance because it doesn't add a new reference to the
state value, and additional references can inhibit in-place updates of data.
-/
@[always_inline, inline]
protected def modifyGet (f : σα × σ) : StateT σ m α :=
fun s => pure (f s)
/--
Runs an action from the underlying monad in the monad with state. The state is not modified.
This function is typically implicitly accessed via a `MonadLiftT` instance as part of [automatic
lifting](lean-manual://section/monad-lifting).
-/
@[always_inline, inline]
protected def lift {α : Type u} (t : m α) : StateT σ m α :=
fun s => do let a ← t; pure (a, s)

View file

@ -6,24 +6,45 @@ Authors: Leonardo de Moura
prelude
import Init.Control.Lawful.Basic
set_option linter.missingDocs true
/-!
The State monad transformer using CPS style.
-/
/--
An alternative implementation of a state monad transformer that internally uses continuation passing
style instead of tuples.
-/
def StateCpsT (σ : Type u) (m : Type u → Type v) (α : Type u) := (δ : Type u) → σ → (ασ → m δ) → m δ
namespace StateCpsT
variable {α σ : Type u} {m : Type u → Type v}
/--
Runs a stateful computation that's represented using continuation passing style by providing it with
an initial state and a continuation.
-/
@[always_inline, inline]
def runK (x : StateCpsT σ m α) (s : σ) (k : ασ → m β) : m β :=
x _ s k
/--
Executes an action from a monad with added state in the underlying monad `m`. Given an initial
state, it returns a value paired with the final state.
While the state is internally represented in continuation passing style, the resulting value is the
same as for a non-CPS state monad.
-/
@[always_inline, inline]
def run [Monad m] (x : StateCpsT σ m α) (s : σ) : m (α × σ) :=
runK x s (fun a s => pure (a, s))
/--
Executes an action from a monad with added state in the underlying monad `m`. Given an initial
state, it returns a value, discarding the final state.
-/
@[always_inline, inline]
def run' [Monad m] (x : StateCpsT σ m α) (s : σ) : m α :=
runK x s (fun a _ => pure a)
@ -43,6 +64,12 @@ instance : MonadStateOf σ (StateCpsT σ m) where
set s := fun _ _ k => k ⟨⟩ s
modifyGet f := fun _ s k => let (a, s) := f s; k a s
/--
Runs an action from the underlying monad in the monad with state. The state is not modified.
This function is typically implicitly accessed via a `MonadLiftT` instance as part of [automatic
lifting](lean-manual://section/monad-lifting).
-/
@[always_inline, inline]
protected def lift [Monad m] (x : m α) : StateCpsT σ m α :=
fun _ s k => x >>= (k . s)

View file

@ -8,10 +8,23 @@ The State monad transformer using IO references.
prelude
import Init.System.ST
set_option linter.missingDocs true
/--
A state monad that uses an actual mutable reference cell (i.e. an `ST.Ref ω σ`).
The macro `StateRefT σ m α` infers `ω` from `m`. It should normally be used instead.
-/
def StateRefT' (ω : Type) (σ : Type) (m : Type → Type) (α : Type) : Type := ReaderT (ST.Ref ω σ) m α
/-! Recall that `StateRefT` is a macro that infers `ω` from the `m`. -/
/--
Executes an action from a monad with added state in the underlying monad `m`. Given an initial
state, it returns a value paired with the final state.
The monad `m` must support `ST` effects in order to create and mutate reference cells.
-/
@[always_inline, inline]
def StateRefT'.run {ω σ : Type} {m : Type → Type} [Monad m] [MonadLiftT (ST ω) m] {α : Type} (x : StateRefT' ω σ m α) (s : σ) : m (α × σ) := do
let ref ← ST.mkRef s
@ -19,6 +32,12 @@ def StateRefT'.run {ω σ : Type} {m : Type → Type} [Monad m] [MonadLiftT (ST
let s ← ref.get
pure (a, s)
/--
Executes an action from a monad with added state in the underlying monad `m`. Given an initial
state, it returns a value, discarding the final state.
The monad `m` must support `ST` effects in order to create and mutate reference cells.
-/
@[always_inline, inline]
def StateRefT'.run' {ω σ : Type} {m : Type → Type} [Monad m] [MonadLiftT (ST ω) m] {α : Type} (x : StateRefT' ω σ m α) (s : σ) : m α := do
let (a, _) ← x.run s
@ -27,6 +46,12 @@ def StateRefT'.run' {ω σ : Type} {m : Type → Type} [Monad m] [MonadLiftT (ST
namespace StateRefT'
variable {ω σ : Type} {m : Type → Type} {α : Type}
/--
Runs an action from the underlying monad in the monad with state. The state is not modified.
This function is typically implicitly accessed via a `MonadLiftT` instance as part of [automatic
lifting](lean-manual://section/monad-lifting).
-/
@[always_inline, inline]
protected def lift (x : m α) : StateRefT' ω σ m α :=
fun _ => x
@ -36,14 +61,30 @@ instance : MonadLift m (StateRefT' ω σ m) := ⟨StateRefT'.lift⟩
instance (σ m) : MonadFunctor m (StateRefT' ω σ m) := inferInstanceAs (MonadFunctor m (ReaderT _ _))
instance [Alternative m] [Monad m] : Alternative (StateRefT' ω σ m) := inferInstanceAs (Alternative (ReaderT _ _))
/--
Retrieves the current value of the monad's mutable state.
This increments the reference count of the state, which may inhibit in-place updates.
-/
@[inline]
protected def get [MonadLiftT (ST ω) m] : StateRefT' ω σ m σ :=
fun ref => ref.get
/--
Replaces the mutable state with a new value.
-/
@[inline]
protected def set [MonadLiftT (ST ω) m] (s : σ) : StateRefT' ω σ m PUnit :=
fun ref => ref.set s
/--
Applies a function to the current state that both computes a new state and a value. The new state
replaces the current state, and the value is returned.
It is equivalent to a `get` followed by a `set`. However, using `modifyGet` may lead to higher
performance because it doesn't add a new reference to the state value. Additional references can
inhibit in-place updates of data.
-/
@[inline]
protected def modifyGet [MonadLiftT (ST ω) m] (f : σα × σ) : StateRefT' ω σ m α :=
fun ref => ref.modifyGet f

View file

@ -3175,31 +3175,46 @@ instance [Monad m] : [Nonempty α] → Nonempty (m α)
| ⟨x⟩ => ⟨pure x⟩
/--
A function for lifting a computation from an inner `Monad` to an outer `Monad`.
Like Haskell's [`MonadTrans`], but `n` does not have to be a monad transformer.
Alternatively, an implementation of [`MonadLayer`] without `layerInvmap` (so far).
Computations in the monad `m` can be run in the monad `n`. These translations are inserted
automatically by the compiler.
[`MonadTrans`]: https://hackage.haskell.org/package/transformers-0.5.5.0/docs/Control-Monad-Trans-Class.html
[`MonadLayer`]: https://hackage.haskell.org/package/layers-0.1/docs/Control-Monad-Layer.html#t:MonadLayer
Usually, `n` consists of some number of monad transformers applied to `m`, but this is not
mandatory.
New instances should use this class, `MonadLift`. Clients that require one monad to be liftable into
another should instead request `MonadLiftT`, which is the reflexive, transitive closure of
`MonadLift`.
-/
-- Like Haskell's [`MonadTrans`], but `n` does not have to be a monad transformer.
-- Alternatively, an implementation of [`MonadLayer`] without `layerInvmap` (so far).
-- [`MonadTrans`]: https://hackage.haskell.org/package/transformers-0.5.5.0/docs/Control-Monad-Trans-Class.html
-- [`MonadLayer`]: https://hackage.haskell.org/package/layers-0.1/docs/Control-Monad-Layer.html#t:MonadLayer
class MonadLift (m : semiOutParam (Type u → Type v)) (n : Type u → Type w) where
/-- Lifts a value from monad `m` into monad `n`. -/
/-- Translates an action from monad `m` into monad `n`. -/
monadLift : {α : Type u} → m α → n α
/--
The reflexive-transitive closure of `MonadLift`. `monadLift` is used to
transitively lift monadic computations such as `StateT.get` or `StateT.put s`.
Corresponds to Haskell's [`MonadLift`].
Computations in the monad `m` can be run in the monad `n`. These translations are inserted
automatically by the compiler.
[`MonadLift`]: https://hackage.haskell.org/package/layers-0.1/docs/Control-Monad-Layer.html#t:MonadLift
Usually, `n` consists of some number of monad transformers applied to `m`, but this is not
mandatory.
This is the reflexive, transitive closure of `MonadLift`. Clients that require one monad to be
liftable into another should request an instance of `MonadLiftT`. New instances should instead be
defined for `MonadLift` itself.
-/
-- Corresponds to Haskell's [`MonadLift`].
--
-- [`MonadLift`]: https://hackage.haskell.org/package/layers-0.1/docs/Control-Monad-Layer.html#t:MonadLift
class MonadLiftT (m : Type u → Type v) (n : Type u → Type w) where
/-- Lifts a value from monad `m` into monad `n`. -/
/-- Translates an action from monad `m` into monad `n`. -/
monadLift : {α : Type u} → m α → n α
export MonadLiftT (monadLift)
/-- Lifts a value from monad `m` into monad `n`. -/
@[inherit_doc monadLift]
abbrev liftM := @monadLift
@[always_inline]
@ -3236,23 +3251,36 @@ instance (m) : MonadEvalT m m where
monadEval x := x
/--
A functor in the category of monads. Can be used to lift monad-transforming functions.
Based on [`MFunctor`] from the `pipes` Haskell package, but not restricted to
monad transformers. Alternatively, an implementation of [`MonadTransFunctor`].
A way to interpret a fully-polymorphic function in `m` into `n`. Such a function can be thought of
as one that may change the effects in `m`, but can't do so based on specific values that are
provided.
[`MFunctor`]: https://hackage.haskell.org/package/pipes-2.4.0/docs/Control-MFunctor.html
[`MonadTransFunctor`]: http://duairc.netsoc.ie/layers-docs/Control-Monad-Layer.html#t:MonadTransFunctor
Clients of `MonadFunctor` should typically use `MonadFunctorT`, which is the reflexive, transitive
closure of `MonadFunctor`. New instances should be defined for `MonadFunctor.`
-/
-- Based on [`MFunctor`] from the `pipes` Haskell package, but not restricted to
-- monad transformers. Alternatively, an implementation of [`MonadTransFunctor`].
-- [`MFunctor`]: https://hackage.haskell.org/package/pipes-2.4.0/docs/Control-MFunctor.html
-- [`MonadTransFunctor`]: http://duairc.netsoc.ie/layers-docs/Control-Monad-Layer.html#t:MonadTransFunctor
class MonadFunctor (m : semiOutParam (Type u → Type v)) (n : Type u → Type w) where
/-- Lifts a monad morphism `f : {β : Type u} → m β → m β` to
`monadMap f : {α : Type u} → n α → n α`. -/
/--
Lifts a fully-polymorphic transformation of `m` into `n`.
-/
monadMap {α : Type u} : ({β : Type u} → m β → m β) → n α → n α
/-- The reflexive-transitive closure of `MonadFunctor`.
`monadMap` is used to transitively lift `Monad` morphisms. -/
/--
A way to interpret a fully-polymorphic function in `m` into `n`. Such a function can be thought of
as one that may change the effects in `m`, but can't do so based on specific values that are
provided.
This is the reflexive, transitive closure of `MonadFunctor`. It automatically chains together
`MonadFunctor` instances as needed. Clients of `MonadFunctor` should typically use `MonadFunctorT`,
but new instances should be defined for `MonadFunctor`.
-/
class MonadFunctorT (m : Type u → Type v) (n : Type u → Type w) where
/-- Lifts a monad morphism `f : {β : Type u} → m β → m β` to
`monadMap f : {α : Type u} → n α → n α`. -/
/--
Lifts a fully-polymorphic transformation of `m` into `n`.
-/
monadMap {α : Type u} : ({β : Type u} → m β → m β) → n α → n α
export MonadFunctorT (monadMap)
@ -3331,7 +3359,7 @@ handlers do not have exception type annotations.
-/
class MonadExcept (ε : outParam (Type u)) (m : Type v → Type w) where
/--
Throws an exception of type `ε` to the nearest enclosing `catch`.
Throws an exception of type `ε` to the nearest enclosing handler.
-/
throw {α : Type v} : ε → m α
/--
@ -3371,10 +3399,11 @@ instance [MonadExcept ε m] {α : Type v} : OrElse (m α) where
end MonadExcept
/--
An implementation of Haskell's [`ReaderT`]. This is a monad transformer which
equips a monad with additional read-only state, of type `ρ`.
Adds the ability to access a read-only value of type `ρ` to a monad. The value can be locally
overridden by `withReader`, but it cannot be mutated.
[`ReaderT`]: https://hackage.haskell.org/package/transformers-0.5.5.0/docs/Control-Monad-Trans-Reader.html#t:ReaderT
Actions in the resulting monad are functions that take the local value as a parameter, returning
ordinary actions in `m`.
-/
def ReaderT (ρ : Type u) (m : Type u → Type v) (α : Type u) : Type (max u v) :=
ρ → m α
@ -3383,8 +3412,7 @@ instance (ρ : Type u) (m : Type u → Type v) (α : Type u) [Inhabited (m α)]
default := fun _ => default
/--
If `x : ReaderT ρ m α` and `r : ρ`, then `x.run r : ρ` runs the monad with the
given reader state.
Executes an action from a monad with a read-only value in the underlying monad `m`.
-/
@[always_inline, inline]
def ReaderT.run {ρ : Type u} {m : Type u → Type v} {α : Type u} (x : ReaderT ρ m α) (r : ρ) : m α :=
@ -3408,17 +3436,26 @@ end
section
variable {ρ : Type u} {m : Type u → Type v}
/-- `(← read) : ρ` gets the read-only state of a `ReaderT ρ`. -/
/--
Retrieves the reader monad's local value. Typically accessed via `read`, or via `readThe` when more
than one local value is available.
-/
@[always_inline, inline]
protected def read [Monad m] : ReaderT ρ m ρ :=
pure
/-- The `pure` operation of the `ReaderT` monad. -/
/--
Returns the provided value `a`, ignoring the reader monad's local value. Typically used via
`Pure.pure`.
-/
@[always_inline, inline]
protected def pure [Monad m] {α} (a : α) : ReaderT ρ m α :=
fun _ => pure a
/-- The `bind` operation of the `ReaderT` monad. -/
/--
Sequences two reader monad computations. Both are provided with the local value, and the second is
passed the value of the first. Typically used via the `>>=` operator.
-/
@[always_inline, inline]
protected def bind [Monad m] {α β} (x : ReaderT ρ m α) (f : α → ReaderT ρ m β) : ReaderT ρ m β :=
fun r => bind (x r) fun a => f a r
@ -3442,8 +3479,8 @@ instance (ρ m) : MonadFunctor m (ReaderT ρ m) where
monadMap f x := fun ctx => f (x ctx)
/--
`adapt (f : ρ' → ρ)` precomposes function `f` on the reader state of a
`ReaderT ρ`, yielding a `ReaderT ρ'`.
Modifies a reader monad's local value with `f`. The resulting computation applies `f` to the
incoming local value and passes the result to the inner computation.
-/
@[always_inline, inline]
protected def adapt {ρ' α : Type u} (f : ρ' → ρ) : ReaderT ρ m α → ReaderT ρ' m α :=
@ -3453,38 +3490,50 @@ end
end ReaderT
/--
An implementation of Haskell's [`MonadReader`] (sans functional dependency; see also `MonadReader`
in this module). It does not contain `local` because this
function cannot be lifted using `monadLift`. `local` is instead provided by
the `MonadWithReader` class as `withReader`.
Reader monads provide the ability to implicitly thread a value through a computation. The value can
be read, but not written. A `MonadWithReader ρ` instance additionally allows the value to be locally
overridden for a sub-computation.
Note: This class can be seen as a simplification of the more "principled" definition
```
class MonadReaderOf (ρ : Type u) (n : Type u → Type u) where
lift {α : Type u} : ({m : Type u → Type u} → [Monad m] → ReaderT ρ m α) → n α
```
[`MonadReader`]: https://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-Reader-Class.html#t:MonadReader
In this class, `ρ` is a `semiOutParam`, which means that it can influence the choice of instance.
`MonadReader ρ` provides the same operations, but requires that `ρ` be inferrable from `m`.
-/
-- Note: This class can be seen as a simplification of the more "principled" definition
-- ```
-- class MonadReaderOf (ρ : Type u) (n : Type u → Type u) where
-- lift {α : Type u} : ({m : Type u → Type u} → [Monad m] → ReaderT ρ m α) → n α
-- ```
class MonadReaderOf (ρ : semiOutParam (Type u)) (m : Type u → Type v) where
/-- `(← read) : ρ` reads the state out of monad `m`. -/
/-- Retrieves the local value. -/
read : m ρ
/--
Like `read`, but with `ρ` explicit. This is useful if a monad supports
`MonadReaderOf` for multiple different types `ρ`.
Reader monads provide the ability to implicitly thread a value through a computation. The value can
be read, but not written. A `MonadWithReader ρ` instance additionally allows the value to be locally
overridden for a sub-computation.
In this class, `ρ` is an `outParam`, which means that it is inferred from `m`. `MonadReaderOf ρ`
provides the same operations, but allows `ρ` to influence instance synthesis.
-/
class MonadReader (ρ : outParam (Type u)) (m : Type u → Type v) where
/--
Retrieves the local value.
Use `readThe` to explicitly specify a type when more than one value is available.
-/
read : m ρ
export MonadReader (read)
/--
Retrieves the local value whose type is `ρ`. This is useful when a monad supports reading more that
one type of value.
Use `read` for a version that expects the type `ρ` to be inferred from `m`.
-/
@[always_inline, inline]
def readThe (ρ : Type u) {m : Type u → Type v} [MonadReaderOf ρ m] : m ρ :=
MonadReaderOf.read
/-- Similar to `MonadReaderOf`, but `ρ` is an `outParam` for convenience. -/
class MonadReader (ρ : outParam (Type u)) (m : Type u → Type v) where
/-- `(← read) : ρ` reads the state out of monad `m`. -/
read : m ρ
export MonadReader (read)
instance (ρ : Type u) (m : Type u → Type v) [MonadReaderOf ρ m] : MonadReader ρ m where
read := readThe ρ
@ -3495,29 +3544,47 @@ instance {ρ : Type u} {m : Type u → Type v} [Monad m] : MonadReaderOf ρ (Rea
read := ReaderT.read
/--
`MonadWithReaderOf ρ` adds the operation `withReader : (ρρ) → m α → m α`.
This runs the inner `x : m α` inside a modified context after applying the
function `f : ρρ`. In addition to `ReaderT` itself, this operation lifts
over most monad transformers, so it allows us to apply `withReader` to monads
deeper in the stack.
A reader monad that additionally allows the value to be locally overridden.
In this class, `ρ` is a `semiOutParam`, which means that it can influence the choice of instance.
`MonadWithReader ρ` provides the same operations, but requires that `ρ` be inferrable from `m`.
-/
class MonadWithReaderOf (ρ : semiOutParam (Type u)) (m : Type u → Type v) where
/-- `withReader (f : ρρ) (x : m α) : m α` runs the inner `x : m α` inside
a modified context after applying the function `f : ρρ`.-/
withReader {α : Type u} : (ρρ) → m α → m α
/--
Locally modifies the reader monad's value while running an action.
During the inner action `x`, reading the value returns `f` applied to the original value. After
control returns from `x`, the reader monad's value is restored.
-/
withReader {α : Type u} (f : ρρ) (x : m α) : m α
/--
Like `withReader`, but with `ρ` explicit. This is useful if a monad supports
`MonadWithReaderOf` for multiple different types `ρ`.
Locally modifies the reader monad's value while running an action, with the reader monad's local
value type specified explicitly. This is useful when a monad supports reading more than one type of
value.
During the inner action `x`, reading the value returns `f` applied to the original value. After
control returns from `x`, the reader monad's value is restored.
Use `withReader` for a version that expects the local value's type to be inferred from `m`.
-/
@[always_inline, inline]
def withTheReader (ρ : Type u) {m : Type u → Type v} [MonadWithReaderOf ρ m] {α : Type u} (f : ρρ) (x : m α) : m α :=
MonadWithReaderOf.withReader f x
/-- Similar to `MonadWithReaderOf`, but `ρ` is an `outParam` for convenience. -/
/--
A reader monad that additionally allows the value to be locally overridden.
In this class, `ρ` is an `outParam`, which means that it is inferred from `m`. `MonadWithReaderOf ρ`
provides the same operations, but allows `ρ` to influence instance synthesis.
-/
class MonadWithReader (ρ : outParam (Type u)) (m : Type u → Type v) where
/-- `withReader (f : ρρ) (x : m α) : m α` runs the inner `x : m α` inside
a modified context after applying the function `f : ρρ`.-/
/--
Locally modifies the reader monad's value while running an action.
During the inner action `x`, reading the value returns `f` applied to the original value. After
control returns from `x`, the reader monad's value is restored.
-/
withReader {α : Type u} : (ρρ) → m α → m α
export MonadWithReader (withReader)
@ -3532,61 +3599,98 @@ instance {ρ : Type u} {m : Type u → Type v} : MonadWithReaderOf ρ (ReaderT
withReader f x := fun ctx => x (f ctx)
/--
An implementation of [`MonadState`]. In contrast to the Haskell implementation,
we use overlapping instances to derive instances automatically from `monadLift`.
State monads provide a value of a given type (the _state_) that can be retrieved or replaced.
Instances may implement these operations by passing state values around, by using a mutable
reference cell (e.g. `ST.Ref σ`), or in other ways.
[`MonadState`]: https://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-State-Class.html
In this class, `σ` is a `semiOutParam`, which means that it can influence the choice of instance.
`MonadState σ` provides the same operations, but requires that `σ` be inferrable from `m`.
The mutable state of a state monad is visible between multiple `do`-blocks or functions, unlike
[local mutable state](lean-manual://section/do-notation-let-mut) in `do`-notation.
-/
class MonadStateOf (σ : semiOutParam (Type u)) (m : Type u → Type v) where
/-- `(← get) : σ` gets the state out of a monad `m`. -/
/--
Retrieves the current value of the monad's mutable state.
-/
get : m σ
/-- `set (s : σ)` replaces the state with value `s`. -/
/--
Replaces the current value of the mutable state with a new one.
-/
set : σ → m PUnit
/-- `modifyGet (f : σα × σ)` applies `f` to the current state, replaces
the state with the return value, and returns a computed value.
/--
Applies a function to the current state that both computes a new state and a value. The new state
replaces the current state, and the value is returned.
It is equivalent to `do let (a, s) := f (← get); put s; pure a`, but
`modifyGet f` may be preferable because the former does not use the state
linearly (without sufficient inlining). -/
It is equivalent to `do let (a, s) := f (← get); set s; pure a`. However, using `modifyGet` may
lead to higher performance because it doesn't add a new reference to the state value. Additional
references can inhibit in-place updates of data.
-/
modifyGet {α : Type u} : (σ → Prod α σ) → m α
export MonadStateOf (set)
/--
Like `get`, but with `σ` explicit. This is useful if a monad supports
`MonadStateOf` for multiple different types `σ`.
Gets the current state that has the explicitly-provided type `σ`. When the current monad has
multiple state types available, this function selects one of them.
-/
abbrev getThe (σ : Type u) {m : Type u → Type v} [MonadStateOf σ m] : m σ :=
MonadStateOf.get
/--
Like `modify`, but with `σ` explicit. This is useful if a monad supports
`MonadStateOf` for multiple different types `σ`.
Mutates the current state that has the explicitly-provided type `σ`, replacing its value with the
result of applying `f` to it. When the current monad has multiple state types available, this
function selects one of them.
It is equivalent to `do set (f (← get))`. However, using `modify` may lead to higher performance
because it doesn't add a new reference to the state value. Additional references can inhibit
in-place updates of data.
-/
@[always_inline, inline]
abbrev modifyThe (σ : Type u) {m : Type u → Type v} [MonadStateOf σ m] (f : σσ) : m PUnit :=
MonadStateOf.modifyGet fun s => (PUnit.unit, f s)
/--
Like `modifyGet`, but with `σ` explicit. This is useful if a monad supports
`MonadStateOf` for multiple different types `σ`.
Applies a function to the current state that has the explicitly-provided type `σ`. The function both
computes a new state and a value. The new state replaces the current state, and the value is
returned.
It is equivalent to `do let (a, s) := f (← getThe σ); set s; pure a`. However, using `modifyGetThe`
may lead to higher performance because it doesn't add a new reference to the state value. Additional
references can inhibit in-place updates of data.
-/
@[always_inline, inline]
abbrev modifyGetThe {α : Type u} (σ : Type u) {m : Type u → Type v} [MonadStateOf σ m] (f : σ → Prod α σ) : m α :=
MonadStateOf.modifyGet f
/-- Similar to `MonadStateOf`, but `σ` is an `outParam` for convenience. -/
class MonadState (σ : outParam (Type u)) (m : Type u → Type v) where
/-- `(← get) : σ` gets the state out of a monad `m`. -/
get : m σ
/-- `set (s : σ)` replaces the state with value `s`. -/
set : σ → m PUnit
/-- `modifyGet (f : σα × σ)` applies `f` to the current state, replaces
the state with the return value, and returns a computed value.
/--
State monads provide a value of a given type (the _state_) that can be retrieved or replaced.
Instances may implement these operations by passing state values around, by using a mutable
reference cell (e.g. `ST.Ref σ`), or in other ways.
It is equivalent to `do let (a, s) := f (← get); put s; pure a`, but
`modifyGet f` may be preferable because the former does not use the state
linearly (without sufficient inlining). -/
In this class, `σ` is an `outParam`, which means that it is inferred from `m`. `MonadStateOf σ`
provides the same operations, but allows `σ` to influence instance synthesis.
The mutable state of a state monad is visible between multiple `do`-blocks or functions, unlike
[local mutable state](lean-manual://section/do-notation-let-mut) in `do`-notation.
-/
class MonadState (σ : outParam (Type u)) (m : Type u → Type v) where
/--
Retrieves the current value of the monad's mutable state.
-/
get : m σ
/--
Replaces the current value of the mutable state with a new one.
-/
set : σ → m PUnit
/--
Applies a function to the current state that both computes a new state and a value. The new state
replaces the current state, and the value is returned.
It is equivalent to `do let (a, s) := f (← get); set s; pure a`. However, using `modifyGet` may
lead to higher performance because it doesn't add a new reference to the state value. Additional
references can inhibit in-place updates of data.
-/
modifyGet {α : Type u} : (σ → Prod α σ) → m α
export MonadState (get modifyGet)
@ -3597,18 +3701,22 @@ instance (σ : Type u) (m : Type u → Type v) [MonadStateOf σ m] : MonadState
modifyGet f := MonadStateOf.modifyGet f
/--
`modify (f : σσ)` applies the function `f` to the state.
Mutates the current state, replacing its value with the result of applying `f` to it.
It is equivalent to `do set (f (← get))`, but `modify f` may be preferable
because the former does not use the state linearly (without sufficient inlining).
Use `modifyThe` to explicitly select a state type to modify.
It is equivalent to `do set (f (← get))`. However, using `modify` may lead to higher performance
because it doesn't add a new reference to the state value. Additional references can inhibit
in-place updates of data.
-/
@[always_inline, inline]
def modify {σ : Type u} {m : Type u → Type v} [MonadState σ m] (f : σσ) : m PUnit :=
modifyGet fun s => (PUnit.unit, f s)
/--
`getModify f` gets the state, applies function `f`, and returns the old value
of the state. It is equivalent to `get <* modify f` but may be more efficient.
Replaces the state with the result of applying `f` to it. Returns the old value of the state.
It is equivalent to `get <* modify f` but may be more efficient.
-/
@[always_inline, inline]
def getModify {σ : Type u} {m : Type u → Type v} [MonadState σ m] (f : σσ) : m σ :=
@ -3625,13 +3733,16 @@ instance {σ : Type u} {m : Type u → Type v} {n : Type u → Type w} [MonadLif
namespace EStateM
/--
`Result ε σ α` is equivalent to `Except ε α × σ`, but using a single
combined inductive yields a more efficient data representation.
The value returned from a combined state and exception monad in which exceptions do not
automatically roll back the state.
`Result ε σ α` is equivalent to `Except ε α × σ`, but using a single combined inductive type yields
a more efficient data representation.
-/
inductive Result (ε σ α : Type u) where
/-- A success value of type `α`, and a new state `σ`. -/
/-- A success value of type `α` and a new state `σ`. -/
| ok : ασ → Result ε σ α
/-- A failure value of type `ε`, and a new state `σ`. -/
/-- An exception of type `ε` and a new state `σ`. -/
| error : ε → σ → Result ε σ α
variable {ε σ α : Type u}
@ -3643,8 +3754,11 @@ end EStateM
open EStateM (Result) in
/--
`EStateM ε σ` is a combined error and state monad, equivalent to
`ExceptT ε (StateM σ)` but more efficient.
A combined state and exception monad in which exceptions do not automatically roll back the state.
Instances of `EStateM.Backtrackable` provide a way to roll back some part of the state if needed.
`EStateM ε σ` is equivalent to `ExceptT ε (StateM σ)`, but it is more efficient.
-/
def EStateM (ε σ α : Type u) := σ → Result ε σ α
@ -3655,45 +3769,53 @@ variable {ε σ α β : Type u}
instance [Inhabited ε] : Inhabited (EStateM ε σ α) where
default := fun s => Result.error default s
/-- The `pure` operation of the `EStateM` monad. -/
/--
Returns a value without modifying the state or throwing an exception.
-/
@[always_inline, inline]
protected def pure (a : α) : EStateM ε σ α := fun s =>
Result.ok a s
/-- The `set` operation of the `EStateM` monad. -/
@[always_inline, inline]
@[always_inline, inline, inherit_doc MonadState.set]
protected def set (s : σ) : EStateM ε σ PUnit := fun _ =>
Result.ok ⟨⟩ s
/-- The `get` operation of the `EStateM` monad. -/
@[always_inline, inline]
@[always_inline, inline, inherit_doc MonadState.get]
protected def get : EStateM ε σ σ := fun s =>
Result.ok s s
/-- The `modifyGet` operation of the `EStateM` monad. -/
@[always_inline, inline]
@[always_inline, inline, inherit_doc MonadState.modifyGet]
protected def modifyGet (f : σ → Prod α σ) : EStateM ε σ α := fun s =>
match f s with
| (a, s) => Result.ok a s
/-- The `throw` operation of the `EStateM` monad. -/
@[always_inline, inline]
@[always_inline, inline, inherit_doc MonadExcept.throw]
protected def throw (e : ε) : EStateM ε σ α := fun s =>
Result.error e s
/--
Auxiliary instance for saving/restoring the "backtrackable" part of the state.
Here `σ` is the state, and `δ` is some subpart of it, and we have a
getter and setter for it (a "lens" in the Haskell terminology).
Exception handlers in `EStateM` save some part of the state, determined by `δ`, and restore it if an
exception is caught. By default, `δ` is `Unit`, and no information is saved.
-/
class Backtrackable (δ : outParam (Type u)) (σ : Type u) where
/-- `save s : δ` retrieves a copy of the backtracking state out of the state. -/
/--
Extracts the information in the state that should be rolled back if an exception is handled.
-/
save : σ → δ
/-- `restore (s : σ) (x : δ) : σ` applies the old backtracking state `x` to
the state `s` to get a backtracked state `s'`. -/
/--
Updates the current state with the saved information that should be rolled back. This updated
state becomes the current state when an exception is handled.
-/
restore : σ → δ → σ
/-- Implementation of `tryCatch` for `EStateM` where the state is `Backtrackable`. -/
/--
Handles exceptions thrown in the combined error and state monad.
The `Backtrackable δ σ` instance is used to save a snapshot of part of the state prior to running
`x`. If an exception is caught, the state is updated with the saved snapshot, rolling back part of
the state. If no instance of `Backtrackable` is provided, a fallback instance in which `δ` is `Unit`
is used, and no information is rolled back.
-/
@[always_inline, inline]
protected def tryCatch {δ} [Backtrackable δ σ] {α} (x : EStateM ε σ α) (handle : ε → EStateM ε σ α) : EStateM ε σ α := fun s =>
let d := Backtrackable.save s
@ -3701,7 +3823,14 @@ protected def tryCatch {δ} [Backtrackable δ σ] {α} (x : EStateM ε σ α) (h
| Result.error e s => handle e (Backtrackable.restore s d)
| ok => ok
/-- Implementation of `orElse` for `EStateM` where the state is `Backtrackable`. -/
/--
Failure handling that does not depend on specific exception values.
The `Backtrackable δ σ` instance is used to save a snapshot of part of the state prior to running
`x₁`. If an exception is caught, the state is updated with the saved snapshot, rolling back part of
the state. If no instance of `Backtrackable` is provided, a fallback instance in which `δ` is `Unit`
is used, and no information is rolled back.
-/
@[always_inline, inline]
protected def orElse {δ} [Backtrackable δ σ] (x₁ : EStateM ε σ α) (x₂ : Unit → EStateM ε σ α) : EStateM ε σ α := fun s =>
let d := Backtrackable.save s;
@ -3709,28 +3838,37 @@ protected def orElse {δ} [Backtrackable δ σ] (x₁ : EStateM ε σ α) (x₂
| Result.error _ s => x₂ () (Backtrackable.restore s d)
| ok => ok
/-- Map the exception type of a `EStateM ε σ α` by a function `f : ε → ε'`. -/
/--
Transforms exceptions with a function, doing nothing on successful results.
-/
@[always_inline, inline]
def adaptExcept {ε' : Type u} (f : ε → ε') (x : EStateM ε σ α) : EStateM ε' σ α := fun s =>
match x s with
| Result.error e s => Result.error (f e) s
| Result.ok a s => Result.ok a s
/-- The `bind` operation of the `EStateM` monad. -/
/--
Sequences two `EStateM ε σ` actions, passing the returned value from the first into the second.
-/
@[always_inline, inline]
protected def bind (x : EStateM ε σ α) (f : α → EStateM ε σ β) : EStateM ε σ β := fun s =>
match x s with
| Result.ok a s => f a s
| Result.error e s => Result.error e s
/-- The `map` operation of the `EStateM` monad. -/
/--
Transforms the value returned from an `EStateM ε σ` action using a function.
-/
@[always_inline, inline]
protected def map (f : α → β) (x : EStateM ε σ α) : EStateM ε σ β := fun s =>
match x s with
| Result.ok a s => Result.ok (f a) s
| Result.error e s => Result.error e s
/-- The `seqRight` operation of the `EStateM` monad. -/
/--
Sequences two `EStateM ε σ` actions, running `x` before `y`. The first action's return value is
ignored.
-/
@[always_inline, inline]
protected def seqRight (x : EStateM ε σ α) (y : Unit → EStateM ε σ β) : EStateM ε σ β := fun s =>
match x s with
@ -3756,13 +3894,16 @@ instance {δ} [Backtrackable δ σ] : MonadExceptOf ε (EStateM ε σ) where
throw := EStateM.throw
tryCatch := EStateM.tryCatch
/-- Execute an `EStateM` on initial state `s` to get a `Result`. -/
/--
Executes an `EStateM` action with the initial state `s`. The returned value includes the final state
and indicates whether an exception was thrown or a value was returned.
-/
@[always_inline, inline]
def run (x : EStateM ε σ α) (s : σ) : Result ε σ α := x s
/--
Execute an `EStateM` on initial state `s` for the returned value `α`.
If the monadic action throws an exception, returns `none` instead.
Executes an `EStateM` with the initial state `s` for the returned value `α`, discarding the final
state. Returns `none` if an unhandled exception was thrown.
-/
@[always_inline, inline]
def run' (x : EStateM ε σ α) (s : σ) : Option α :=
@ -3777,10 +3918,11 @@ def run' (x : EStateM ε σ α) (s : σ) : Option α :=
@[inline] def dummyRestore : σ → PUnit → σ := fun s _ => s
/--
Dummy default instance. This makes every `σ` trivially "backtrackable"
by doing nothing on backtrack. Because this is the first declared instance
of `Backtrackable _ σ`, it will be picked only if there are no other
`Backtrackable _ σ` instances registered.
A fallback `Backtrackable` instance that saves no information from a state. This allows every type
to be used as a state in `EStateM`, with no rollback.
Because this is the first declared instance of `Backtrackable _ σ`, it will be picked only if there
are no other `Backtrackable _ σ` instances registered.
-/
instance nonBacktrackable : Backtrackable PUnit σ where
save := dummySave

View file

@ -34,7 +34,7 @@ partial def expandCoe (e : Expr) : MetaM Expr :=
register_builtin_option autoLift : Bool := {
defValue := true
descr := "insert monadic lifts (i.e., `liftM` and coercions) when needed"
descr := "Insert monadic lifts (i.e., `liftM` and coercions) when needed."
}
/-- Coerces `expr` to `expectedType` using `CoeT`. -/

View file

@ -1009,6 +1009,12 @@ def macroArg := termParser maxPrec
def macroDollarArg := leading_parser "$" >> termParser 10
def macroLastArg := macroDollarArg <|> macroArg
/--
A state monad that uses an actual mutable reference cell (i.e. an `ST.Ref`).
This is syntax, rather than a function, to make it easier to use. Its elaborator synthesizes an
appropriate parameter for the underlying monad's `ST` effects, then passes it to `StateRefT'`.
-/
-- Macro for avoiding exponentially big terms when using `STWorld`
@[builtin_term_parser] def stateRefT := leading_parser
"StateRefT " >> macroArg >> ppSpace >> macroLastArg