use crate::traits::{GenType, Monoid};
pub struct Writer<'a, W, A>
where
W: Monoid,
{
pub(crate) run_writer: Option<Box<dyn FnOnce(W) -> (A, W) + 'a>>,
}
impl<'a, W, A> Writer<'a, W, A>
where
W: Monoid + 'a,
A: 'a,
{
pub fn new((a, wt): (A, W)) -> Self {
Self {
run_writer: Some(Box::new(move |w| (a, w.mappend(wt)))),
}
}
pub fn eval_writer(self, w: W) -> A {
self.run_writer
.map(|writer| writer(w))
.map(|(a, _)| a)
.expect("Writer never empty")
}
pub fn run_with(self, w: W) -> (A, W) {
self.run_writer
.map(|writer| writer(w))
.expect("Writer never empty")
}
pub fn exec_writer(self, w: W) -> W {
self.run_writer
.map(|writer| writer(w))
.map(|(_, w)| w)
.expect("Writer never empty")
}
pub fn run(self) -> (A, W) {
self.run_writer
.map(|writer_f| writer_f(W::mempty()))
.expect("Writer never empty")
}
pub fn map_writer<F, B, V>(self, f: F) -> Writer<'a, V, B>
where
F: FnOnce((A, W)) -> (B, V) + 'a,
V: Monoid,
{
Writer {
run_writer: Some(Box::new(move |v: V| {
let (a, w) = self.run();
let (b, vt) = f((a, w));
(b, v.mappend(vt))
})),
}
}
}
impl<'a, W, A> GenType for Writer<'a, W, A>
where
W: Monoid + 'a,
A: 'a,
{
type Type<B> = Writer<'a, W, B>;
}