//! Implementation of the `Writer` effect
let { Eff, inject_rest, ? } = import! std.effect
let monoid @ { Monoid } = import! std.monoid
let { (<>) } = import! std.semigroup
let { wrap } = import! std.applicative
let { (<<) } = import! std.function
/// The `Writer` effect allows the computations to output values of type `s`
type Writer s r a =
| Tell : s -> Writer s r ()
.. r
#[inline(never)]
let extract_writer x : forall s . [| writer : Writer s | r |] a -> Writer s r a = convert_variant! x
#[inline(never)]
let send_writer f : Writer s r a -> Eff [| writer : Writer s | r |] a =
Impure (convert_effect! writer f) Pure
/// Outputs `s`
let tell s : forall s . s -> Eff [| writer : Writer s | r |] () =
send_writer (Tell s)
/// Eliminates `Writer`, returning the output and computed value. Each output through `tell` are
/// joined via its `Monoid` instance
let run_writer eff : forall s .
[Monoid s] -> Eff [| writer : Writer s | r |] a -> Eff [| | r |] { value : a, writer : s }
=
let loop writer ve : s -> Eff [| writer : Writer s | r |] a -> Eff [| | r |] _ =
match ve with
| Pure value -> wrap { value, writer }
| Impure e f ->
match extract_writer e with
| Tell w ->
loop (writer <> w) (f ())
| rest ->
Impure (inject_rest rest) (loop writer << f)
loop monoid.empty eff
{
Writer,
tell,
run_writer,
}