use tytro::tytro;
#[tytro]
enum List<T> {
Nil,
Cons(T, Self),
}
impl List<u32> {
fn range(x: u32) -> Self {
match x {
0 => ListF::Nil,
_ => ListF::Cons(x - 1, Self::range(x - 1)),
}
.build()
}
}
impl<T> List<T> {
fn concat(self, rhs: Self) -> Self {
self.foldr(rhs, &|x, rhs| ListF::Cons(x, rhs).build())
}
fn foldr<R>(self, init: R, f: &impl Fn(T, R) -> R) -> R {
match self.get() {
ListF::Nil => init,
ListF::Cons(x, xs) => f(x, xs.foldr(init, f)),
}
}
}
impl ListRef<'_, u32> {
fn sum(self) -> u32 {
self.foldl(0, |sum, &x| sum + x)
}
}
impl<T> ListRef<'_, T> {
fn foldl<R>(self, init: R, f: impl Fn(R, &T) -> R) -> R {
match self.get_ref() {
ListFRef::Nil => init,
ListFRef::Cons(x, xs) => xs.foldl(f(init, x), f),
}
}
}
#[test]
fn test_nat() {
let l1 = List::range(10);
let l2 = ListF::Cons(114, ListF::Cons(514, ListF::Nil.build()).build()).build();
assert_eq!(l1.as_ref().sum(), 45);
assert_eq!(l2.as_ref().sum(), 628);
assert_eq!(l1.concat(l2).as_ref().sum(), 673);
}