use crate::{Cons, HList, Nil};
use super::{FoldFn, Folder};
pub trait Fold<Accumulator, Folder>: HList {
fn fold(self, init: Accumulator, folder: Folder) -> Accumulator;
}
impl<A, F> Fold<A, F> for Nil {
fn fold(self, init: A, _: F) -> A {
init
}
}
impl<A, F, Head, Tail> Fold<A, F> for Cons<Head, Tail>
where
F: FnMut(A, Head) -> A,
Tail: Fold<A, F>,
{
fn fold(self, init: A, mut folder: F) -> A {
let Cons(head, tail) = self;
let init = folder(init, head);
tail.fold(init, folder)
}
}
impl<A, FHead, FTail, Head, Tail> Fold<A, Cons<FHead, FTail>> for Cons<Head, Tail>
where
FHead: FnOnce(A, Head) -> A,
Tail: Fold<A, FTail>,
{
fn fold(self, init: A, folder: Cons<FHead, FTail>) -> A {
let Cons(head, tail) = self;
let Cons(folder_head, folder_tail) = folder;
let init = folder_head(init, head);
tail.fold(init, folder_tail)
}
}
impl<A, F, Head, Tail> Fold<A, Folder<F>> for Cons<Head, Tail>
where
F: FoldFn<A, Head>,
Tail: Fold<A, Folder<F>>,
{
fn fold(self, init: A, mut folder: Folder<F>) -> A {
let Cons(head, tail) = self;
let init = folder.fold(init, head);
tail.fold(init, folder)
}
}