//! 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, }