use crate::effect::writer::boxed::BoxedWriterEffect;
use crate::effect::writer::WriterEffect;
use crate::Monoid;
pub fn traverse_writer<T, U, E, Env, W, F, Eff>(
items: Vec<T>,
f: F,
) -> BoxedWriterEffect<Vec<U>, E, Env, W>
where
T: Send + 'static,
U: Send + 'static,
E: Send + 'static,
Env: Clone + Send + Sync + 'static,
W: Monoid + Send + 'static,
F: Fn(T) -> Eff + Send + 'static,
Eff: WriterEffect<Output = U, Error = E, Env = Env, Writes = W> + Send + 'static,
{
BoxedWriterEffect::new(TraverseWriter { items, f })
}
struct TraverseWriter<T, F> {
items: Vec<T>,
f: F,
}
impl<T, U, E, Env, W, F, Eff> crate::effect::Effect for TraverseWriter<T, F>
where
T: Send + 'static,
U: Send + 'static,
E: Send + 'static,
Env: Clone + Send + Sync + 'static,
W: Monoid + Send + 'static,
F: Fn(T) -> Eff + Send + 'static,
Eff: WriterEffect<Output = U, Error = E, Env = Env, Writes = W> + Send + 'static,
{
type Output = Vec<U>;
type Error = E;
type Env = Env;
async fn run(self, env: &Self::Env) -> Result<Self::Output, Self::Error> {
let (result, _writes) = self.run_writer(env).await;
result
}
}
impl<T, U, E, Env, W, F, Eff> WriterEffect for TraverseWriter<T, F>
where
T: Send + 'static,
U: Send + 'static,
E: Send + 'static,
Env: Clone + Send + Sync + 'static,
W: Monoid + Send + 'static,
F: Fn(T) -> Eff + Send + 'static,
Eff: WriterEffect<Output = U, Error = E, Env = Env, Writes = W> + Send + 'static,
{
type Writes = W;
async fn run_writer(
self,
env: &Self::Env,
) -> (Result<Self::Output, Self::Error>, Self::Writes) {
let mut results = Vec::with_capacity(self.items.len());
let mut all_writes = W::empty();
for item in self.items {
let effect = (self.f)(item);
let (result, writes) = effect.run_writer(env).await;
all_writes = all_writes.combine(writes);
match result {
Ok(value) => results.push(value),
Err(e) => return (Err(e), all_writes),
}
}
(Ok(results), all_writes)
}
}
pub fn fold_writer<T, A, E, Env, W, F, Eff>(
items: Vec<T>,
init: A,
f: F,
) -> BoxedWriterEffect<A, E, Env, W>
where
T: Send + 'static,
A: Send + 'static,
E: Send + 'static,
Env: Clone + Send + Sync + 'static,
W: Monoid + Send + 'static,
F: Fn(A, T) -> Eff + Send + 'static,
Eff: WriterEffect<Output = A, Error = E, Env = Env, Writes = W> + Send + 'static,
{
BoxedWriterEffect::new(FoldWriter { items, init, f })
}
struct FoldWriter<T, A, F> {
items: Vec<T>,
init: A,
f: F,
}
impl<T, A, E, Env, W, F, Eff> crate::effect::Effect for FoldWriter<T, A, F>
where
T: Send + 'static,
A: Send + 'static,
E: Send + 'static,
Env: Clone + Send + Sync + 'static,
W: Monoid + Send + 'static,
F: Fn(A, T) -> Eff + Send + 'static,
Eff: WriterEffect<Output = A, Error = E, Env = Env, Writes = W> + Send + 'static,
{
type Output = A;
type Error = E;
type Env = Env;
async fn run(self, env: &Self::Env) -> Result<Self::Output, Self::Error> {
let (result, _writes) = self.run_writer(env).await;
result
}
}
impl<T, A, E, Env, W, F, Eff> WriterEffect for FoldWriter<T, A, F>
where
T: Send + 'static,
A: Send + 'static,
E: Send + 'static,
Env: Clone + Send + Sync + 'static,
W: Monoid + Send + 'static,
F: Fn(A, T) -> Eff + Send + 'static,
Eff: WriterEffect<Output = A, Error = E, Env = Env, Writes = W> + Send + 'static,
{
type Writes = W;
async fn run_writer(
self,
env: &Self::Env,
) -> (Result<Self::Output, Self::Error>, Self::Writes) {
let mut accumulator = self.init;
let mut all_writes = W::empty();
for item in self.items {
let effect = (self.f)(accumulator, item);
let (result, writes) = effect.run_writer(env).await;
all_writes = all_writes.combine(writes);
match result {
Ok(value) => accumulator = value,
Err(e) => return (Err(e), all_writes),
}
}
(Ok(accumulator), all_writes)
}
}