Control.Writer
The canonical Writer(w) effect: accumulate output on the side.
tell(m) appends m to a log the producer never sees; run_writer returns the computation’s result paired with the whole log in emission order. The handler threads the growing log as a parameter (tail-resumptive, so it fuses), so nothing shared or mutable is involved. eval_writer keeps only the result, exec_writer only the log, and listen/censor observe or rewrite an inner computation’s log while staying inside the effect. Opt-in: not in Base.
Effects
Writer
effect Writer(w)
tell(w) : Unit
Append one item of type w to the accumulated log.
Functions and Values
run_writer
run_writer : forall e0 a b. (() -> a ! {Control.Writer.Writer(b), e0}) -> (a, List(b)) ! {e0}
Run action, collecting every tell into a log, and return the computation’s result paired with that log in emission order.
run_writer(\() -> tells(["started", "finished"]))
((), [started, finished])
eval_writer
eval_writer : forall e0 a b. (() -> a ! {Control.Writer.Writer(b), e0}) -> a ! {e0}
Run action and keep only its result, discarding the log.
exec_writer
exec_writer : forall e0 a b. (() -> a ! {Control.Writer.Writer(b), e0}) -> List(b) ! {e0}
Run action and keep only the log, discarding the result.
listen
listen : forall e0 a b. (() -> a ! {Control.Writer.Writer(b), Control.Writer.Writer(b), e0}) -> (a, List(b)) ! {Control.Writer.Writer(b), e0}
Run action, re-emit its log unchanged, and return the result paired with that log, so an outer writer both observes and keeps the inner output.
censor
censor : forall e0 a b. ((List(a)) -> List(a), () -> b ! {Control.Writer.Writer(a), Control.Writer.Writer(a), e0}) -> b ! {Control.Writer.Writer(a), e0}
Run action, rewrite its whole log with f, and re-emit the rewritten log, returning the result. The rewrite sees the log in emission order.
exec_writer(\() -> censor(reverse, \() -> tells(["a", "b"])))
[b, a]
tells
tells : forall a. (List(a)) -> Unit ! {Control.Writer.Writer(a)}
Emit every item of log in order.