cross: list: extend fold to work by reference.

This commit is contained in:
2022-08-15 23:51:19 -07:00
parent 7704eb623a
commit a8acf6cbb8
2 changed files with 54 additions and 1 deletions

View File

@@ -309,6 +309,7 @@ pub trait SplitHead {
type Head;
type Tail;
fn split(self) -> (Self::Head, Self::Tail);
fn split_ref<'a>(&'a self) -> (&'a Self::Head, &'a Self::Tail);
}
impl<H, T> SplitHead for Node<H, T> {
type Head = H;
@@ -316,6 +317,9 @@ impl<H, T> SplitHead for Node<H, T> {
fn split(self) -> (Self::Head, Self::Tail) {
(self.head, self.tail)
}
fn split_ref<'a>(&'a self) -> (&'a Self::Head, &'a Self::Tail) {
(&self.head, &self.tail)
}
}
/// these are exported for the convenience of potential consumers: not needed internally

View File

@@ -97,7 +97,7 @@ where
// - [x] map (calls into fold, with the accumulator being Appendable::append)
// - [ ] visit (calls into fold, with a no-op accumulator)
// - [ ] visit_ref, visit_mut (calls as_ref/as_mut, then visit)
// - [ ] enumerate (calls fold, with the accumulator being a Peano counter + value copy)
// - [x] enumerate (calls fold, with the accumulator being a Peano counter + value copy)
pub trait ListConsumer<L> {
type Output;
@@ -113,6 +113,7 @@ pub trait FoldOp<State, V> {
pub struct FoldImpl<Op, State>(Op, State);
//////// fold by-value
impl<Op, State> ListConsumer<Empty> for FoldImpl<Op, State> {
type Output = State;
fn consume(self, _l: Empty) -> Self::Output {
@@ -134,6 +135,28 @@ where
}
}
//////// fold by-ref
impl<Op, State> ListConsumer<&Empty> for FoldImpl<Op, State> {
type Output = State;
fn consume(self, _l: &Empty) -> Self::Output {
self.1
}
}
impl<'a, H, T, Op, State> ListConsumer<&'a Node<H, T>> for FoldImpl<Op, State>
where
Op: FoldOp<State, &'a H>,
FoldImpl<Op, Op::Output>: ListConsumer<&'a T>,
{
type Output = <FoldImpl<Op, Op::Output> as ListConsumer<&'a T>>::Output;
fn consume(self, l: &'a Node<H, T>) -> Self::Output {
let FoldImpl(op, state) = self;
let (head, tail) = l.split_ref();
let next_state = op.feed(state, head);
FoldImpl(op, next_state).consume(tail)
}
}
pub trait Fold<Op, Init> {
type Output;
fn fold(self, op: Op, init: Init) -> Self::Output;
@@ -309,6 +332,32 @@ mod test {
assert_eq!(list.fold(Sum, 2i32), 28f32);
}
#[derive(PartialEq)]
struct NotCopy(i32);
struct SumRef;
impl FoldOp<i32, &NotCopy> for SumRef {
type Output = i32;
fn feed(&self, prev: i32, next: &NotCopy) -> Self::Output {
prev + next.0
}
}
impl FoldOp<i32, &i32> for SumRef {
type Output = i32;
fn feed(&self, prev: i32, next: &i32) -> Self::Output {
prev + *next
}
}
#[test]
fn fold_ref() {
let list = &(3i32, NotCopy(4i32), 5i32).into_list();
assert_eq!(list.fold(SumRef, 2i32), 14i32);
assert!(list == list); // just check that it wasn't consumed
}
#[test]
fn reverse_empty() {
assert!(Empty::default().reverse() == Empty::default());