use monadify::applicative::kind::Applicative;
use monadify::identity::{Identity, IdentityKind};
use monadify::mdo;
use monadify::monad::kind::Bind;
use monadify::transformers::writer::{Writer, WriterTKind};
use proptest::prelude::*;
type WKind = WriterTKind<Vec<i32>, IdentityKind>;
type Logged<A> = Writer<Vec<i32>, A>;
fn tell(n: i32) -> Logged<()> {
WKind::tell(vec![n])
}
fn run_id<A>(w: Logged<A>) -> (A, Vec<i32>) {
let Identity(pair) = w.run_writer_t;
pair
}
#[test]
fn writer_mdo_accumulates_log() {
let comp: Logged<i32> = mdo! {
WKind;
_ <- tell(1);
_ <- tell(2);
_ <- tell(3);
WKind::pure(42)
};
assert_eq!(run_id(comp), (42, vec![1, 2, 3]));
}
#[test]
fn writer_mdo_interleaves_values_and_log() {
let comp: Logged<i32> = mdo! {
WKind;
_ <- tell(10);
x <- WKind::writer(5, vec![20]);
_ <- tell(30);
WKind::pure(x + 1)
};
assert_eq!(run_id(comp), (6, vec![10, 20, 30]));
}
#[test]
fn writer_mdo_equivalent_to_manual_bind() {
let via_mdo: Logged<i32> = mdo! {
WKind;
_ <- tell(1);
_ <- tell(2);
WKind::pure(7)
};
let via_bind: Logged<i32> = WKind::bind(tell(1), move |_| {
WKind::bind(tell(2), move |_| WKind::pure(7))
});
assert_eq!(run_id(via_mdo), run_id(via_bind));
}
#[test]
fn writer_mdo_four_step_chain() {
let comp: Logged<i32> = mdo! {
WKind;
_ <- tell(1);
_ <- tell(2);
_ <- tell(3);
_ <- tell(4);
WKind::pure(0)
};
assert_eq!(run_id(comp), (0, vec![1, 2, 3, 4]));
}
proptest! {
#![proptest_config(ProptestConfig { cases: 256, ..ProptestConfig::default() })]
#[test]
fn writer_mdo_matches_manual_over_generated_logs(a in any::<i32>(), b in any::<i32>(), v in any::<i32>()) {
let via_mdo: Logged<i32> = mdo! {
WKind;
_ <- tell(a);
_ <- tell(b);
WKind::pure(v)
};
let via_bind: Logged<i32> =
WKind::bind(tell(a), move |_| WKind::bind(tell(b), move |_| WKind::pure(v)));
prop_assert_eq!(run_id(via_mdo), run_id(via_bind));
}
}