Std.Do weakest-precondition bridge for WriterT #
Provides Std.Do.WP and Std.Do.WPMonad instances for WriterT ω m,
together with @[spec] lemmas for MonadWriter.tell,
MonadLift.monadLift, and WriterT.run. With these in scope, mvcgen
can walk through any do-block in WriterT ω m, treating the writer
log ω as a state component (post-shape (.arg ω ps) where ps is the
inner monad's post-shape).
The bridge supports two parameterizations in parallel:
[EmptyCollection ω] [Append ω] [LawfulAppend ω], which is whatloggingOracle(overWriterT (QueryLog spec) (OracleComp spec)) needs becauseQueryLog specunfolds toList _.[Monoid ω], which is whatcountingOracle/costOracle(overWriterT (QueryCount ι) (OracleComp spec)) need.QueryCount ιunfolds toι → ℕ, and the effective monoid on it is the additive one repackaged as a multiplicativeMonoid(so1represents the all-zero function and*represents pointwise+).ι → ℕhas noAppendinstance, so only the[Monoid ω]parameterization applies there.
The two WP / WPMonad instances live side-by-side and do not overlap on
any currently used target type (List _ has no Monoid instance;
ι → ℕ has no Append instance). To defensively guard against future
overlap on a type carrying both Append and Monoid, the Monoid
variants are registered at low priority so the Append variants win
typeclass resolution whenever both apply.
Implementation #
wp x for x : WriterT ω m α is interpreted as the state-tracking
predicate transformer
PredTrans.pushArg (fun (s : ω) =>
(fun z : α × ω => (z.1, s ++ z.2)) <$> wp (WriterT.run x))
i.e., the writer log is threaded through as state and accumulated via
++. The LawfulAppend law (empty_append, append_empty,
append_assoc) is what makes wp preserve pure and bind.
The underlying predicate-transformer interpretation of a WriterT ω m
computation, factored out so that the WP instance and the proofs
defining WPMonad can refer to it by a single name. The writer log is
threaded through as state and accumulated via ++.
Instances For
Weakest-precondition interpretation of WriterT ω m as a state-tracking
predicate transformer over the writer log ω, with post-shape
(.arg ω ps). The log is accumulated via ++ with identity ∅.
This instance only needs the writer combinators EmptyCollection and
Append to be definable; lawfulness (LawfulAppend) is required for the
WPMonad extension.
WP for WriterT ω m is a monad morphism: it preserves pure and
bind. Requires LawfulAppend ω (so s ++ ∅ = s and ++ is associative)
and lawfulness of the inner monad.
Monoid-based WP interpretation #
The dual parameterization: the writer log ω carries [Monoid ω]
(e.g. QueryCount ι = ι → ℕ with 1 = 0 and * = +). The
interpretation is the same as wpAppend but with 1 / * in place
of ∅ / ++. The monoid laws mul_one, one_mul, mul_assoc play
the role of LawfulAppend.append_empty, empty_append, append_assoc.
The underlying predicate-transformer interpretation of a WriterT ω m
computation when ω is a (multiplicative) monoid. Analogous to
wpAppend but with * / 1 in place of ++ / ∅.
Instances For
WP instance for WriterT ω m under the [Monoid ω] parameterization.
The writer log is threaded through as state and accumulated via * with
identity 1. Does not conflict with instWPAppend because the target
types they fire on are disjoint (List _ has no Monoid, ι → ℕ has
no Append). The priority is set low so that, on a hypothetical ω
carrying both Append and Monoid, instWPAppend wins typeclass
resolution and no WP diamond arises.
WP on WriterT ω m (monoid variant) is a monad morphism: it
preserves pure and bind, using the Monoid laws. Registered at low
priority for the same reason as instWPMonoid.
wp simp lemmas for WriterT operations #
These rewrite wp⟦x⟧ Q for common WriterT operations (tell,
monadLift) into simpler forms involving the inner monad's wp. They are
analogous to Std.Do.WP.monadLift_StateT, etc.
Each simp lemma is provided in two parallel variants matching the two
WP instances for WriterT: the Append-based one (suffix _append,
exposed as the default under the original name for backward
compatibility) and the Monoid-based one (suffix _monoid).
@[spec] lemmas #
The following spec lemmas register WriterT ω m operations with
mvcgen's discrimination tree, so that mvcgen can walk through
do-blocks involving tell, monadLift, and the underlying run
projection.
Spec for MonadWriter.tell in WriterT ω m. The precondition is
Q.1 ⟨⟩ (s ++ w), i.e., the postcondition holds for () with the new
state being the old state appended with the written value w.
Spec for MonadLift.monadLift from m to WriterT ω m. The lifted
computation x : m α runs in the inner monad with the writer state
unchanged (since the lift writes ∅ and s ++ ∅ = s).
Monoid-variant spec for MonadWriter.tell. The postcondition holds
at the new state s * w, where * is the monoid operation on ω.
Monoid-variant spec for MonadLift.monadLift. The lifted
computation runs with the writer state unchanged (the lift writes 1
and s * 1 = s).