1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//! WriterEffect trait definition.
use Future;
use crateEffect;
use crateMonoid;
/// An effect that accumulates values of type `Writes` alongside computation.
///
/// The `Writes` type must be a `Monoid` to support:
/// - Empty writes (`Monoid::empty()`) for effects that don't write
/// - Combining writes (`Semigroup::combine`) when chaining effects
///
/// # Laws
///
/// WriterEffect extends Effect with additional structure:
///
/// 1. **Identity**: `tell(W::empty())` should be equivalent to `pure(())` with empty writes
/// 2. **Homomorphism**: `tell(a).and_then(|_| tell(b))` accumulates `a.combine(b)`
/// 3. **Associativity**: Writes accumulate left-to-right through chains
///
/// # Example
///
/// ```rust
/// use stillwater::effect::writer::prelude::*;
/// use stillwater::effect::prelude::*;
///
/// # tokio_test::block_on(async {
/// let effect = tell_one::<_, String, ()>("log 1".to_string())
/// .and_then(|_| tell_one("log 2".to_string()));
///
/// let (result, logs) = effect.run_writer(&()).await;
/// assert_eq!(result, Ok(()));
/// assert_eq!(logs, vec!["log 1".to_string(), "log 2".to_string()]);
/// # });
/// ```