use crate::{HCons,HNil,ops::*,marker_traits::List,ops::rc::*};
use typenum as tn;
#[derive(Debug,Default)]
pub struct Missing;
literal!{ Missing }
#[derive(Debug,Default)]
pub struct Here;
#[derive(Debug,Default)]
pub struct There<T>(T);
non_calc_literal!{ Here; {T} There<T> }
#[derive(Debug,Default)]
pub struct EmptyP;
defun!{ EmptyP {
(L:List) { _:L } => {Ret, @L::IsEOL };
}}
#[derive(Debug,Default)]
pub struct Tail;
defun!{ Tail {
(L:List) { l:L } => {Ret, @L::Tail = l.split().1 };
}}
#[derive(Debug,Default)]
pub struct Head;
defun!{ Head {
(L:List) { l:L } => {Ret, @L::Head = l.split().0 };
}}
#[derive(Debug,Default)]
pub struct Cons;
defun!{ Cons {
(H,T) { h:H, t:T } => {Ret, @HCons<H,T> = HCons{head:h, tail:t}};
}}
#[derive(Debug,Default)]
pub struct Map;
defun!{ Map {
(Func, L:List) { _:Func, list:L } {
let (h,t) = list.split();
} => {If, {EmptyP, @L}, HNil,
{Cons, {Func, @L::Head = h},
{Map, Func, @L::Tail = t}}};
}}
pub struct MapIter<Func,I>(I, std::marker::PhantomData<Func>);
impl<Func,I:Iterator> MapIter<Func,I> {
pub fn new(iter:I)->Self { MapIter(iter, std::marker::PhantomData) }
}
impl<Func:Eval, I:Iterator> Iterator for MapIter<Func,I>
where sexpr!{Func::Result, @I::Item}: Calc<sexpr!{(), I::Item}>
{
type Item=calc_ty!{Func::Result, @I::Item=it};
fn next(&mut self)->Option<Self::Item> {
self.0.next().map(|it| calc!{Func::Result, @I::Item=it})
}
}
#[derive(Debug,Default)]
pub struct FoldL;
defun!{ FoldL {
(Func,Acc,L:List) {_:Func, acc:Acc, list:L} {
let (h,t) = list.split();
let acc = Rc::new(acc);
} => {If, {EmptyP, @L},
{UnwrapRc, @Rc<Acc> = acc.clone()},
{FoldL, Func,
{Func, {UnwrapRc, @Rc<Acc> = acc},
@L::Head = h},
@L::Tail = t}};
}}
#[derive(Debug,Default)]
pub struct FoldR;
defun!{ FoldR {
(Func,L:List,Init) {_:Func, list:L, init:Init} {
let (h,t) = list.split();
let init = Rc::new(init);
} => {If, {EmptyP, @L},
{UnwrapRc, @Rc<Init> = init.clone()},
{Func, @L::Head = h,
{FoldR, Func,
@L::Tail = t,
{UnwrapRc, @Rc<Init> = init}}}};
}}
#[derive(Debug,Default)]
pub struct MapRef;
defun!{ MapRef {
('a, Func, L:List) { _:Func, list:&'a L } =>
{If, {EmptyP, @L}, HNil,
{Cons, {Func, @ &'a L::Head = &list.head()},
{MapRef, Func, @ &'a L::Tail = &list.tail()}}};
}}
#[derive(Debug,Default)]
pub struct Filter;
defun!{ Filter {
(Func, L:List) { _:Func, list:L } {
let (h,t) = list.split();
} => {If, {EmptyP, @L}, HNil,
{{If, {Func, @L::Head},
@Prepend<L::Head> = Prepend(h),
Ret},
{Filter, Func, @L::Tail = t}}};
}}
#[derive(Debug,Default)]
pub struct Without;
defun!{ Without {
(L:List, Needle:LispId) {_:Needle, l:L} => {Filter, {Partial, IsNot, @Needle}, @L=l};
}}
#[derive(Debug,Default)]
pub struct DifferP;
defun_nocalc!{() DifferP {
(H, T:List) { {_:H; _:T}, {} } => {Ret, @tn::True};
(H, T:List) { {}, {_:H; _:T} } => {Ret, @tn::True};
() { {}, {} } => {Ret, @tn::False};
(H1, T1:List, H2, T2:List) { {_:H1; _:T1}, {_:H2; _:T2} }
=> {If, {Is, @H1, @H2},
{DifferP, @T1, @T2},
@tn::True};
}}
#[derive(Debug,Default)]
pub struct BuildList;
defun!{ BuildList {
(Args:List) {; args:Args } => { Ret, @Args = args };
}}
pub trait CollatedBy<Test> {
type Passed;
type Failed;
fn collate(self)->(Self::Passed, Self::Failed);
}
impl<T> CollatedBy<T> for HNil {
type Passed = HNil;
type Failed = HNil;
fn collate(self)->(Self::Passed, Self::Failed) { (HNil, HNil) }
}
impl<H,T,Test,Step> CollatedBy<Test> for HCons<H,T>
where sexpr!{Test, @H}: Eval<Result = Step>,
Step: CollateStep<Test, H, T>
{
type Passed = Step::Passed;
type Failed = Step::Failed;
fn collate(self)->(Self::Passed, Self::Failed) {
Step::collate_step(self.head, self.tail)
}
}
pub trait CollateStep<Test, H, T> {
type Passed;
type Failed;
fn collate_step(h:H, t:T)->(Self::Passed, Self::Failed);
}
impl<Test, H, T> CollateStep<Test, H, T> for tn::True
where T:CollatedBy<Test> {
type Passed = HCons<H, T::Passed>;
type Failed = T::Failed;
fn collate_step(h:H, t:T)->(Self::Passed, Self::Failed) {
let (pass, fail) = t.collate();
(sexpr_val!{h; pass}, fail)
}
}
impl<Test, H, T> CollateStep<Test, H, T> for tn::False
where T:CollatedBy<Test> {
type Passed = T::Passed;
type Failed = HCons<H, T::Failed>;
fn collate_step(h:H, t:T)->(Self::Passed, Self::Failed) {
let (pass, fail) = t.collate();
(pass, sexpr_val!{h; fail})
}
}
use std::marker::PhantomData;
#[derive(Debug,Default)]
pub struct Collate;
defun!{ Collate {
(Test, L:CollatedBy<Test>) { _:Test, list:L } {
let (pass, fail) = list.collate();
} => {BuildList, @L::Passed = pass, @L::Failed = fail};
}}
#[cfg(test)]
#[derive(Debug,Default)]
pub struct RecTest;
#[cfg(test)]
defun!{ RecTest {
() { _:HNil, x:u32 } => { Ret, @u32 = x };
(H,T) { {_:H; t:T}, x:u32 } => { RecTest, @T = t, @u32 = x+1 };
}}
pub type Reverse = Rev4;
#[derive(Debug,Default)]
pub struct Rev4;
defun!{ Rev4 {
(L:List) { l:L } => {Rev4, @L = l, {}};
(Old: List, New:List) { old:Old, new:New }
{let (h,t) = old.split();
let new = Rc::new(new);} =>
{If, {EmptyP, @Old},
{UnwrapRc, @Rc<New> = new.clone()},
{Rev4, @Old::Tail = t, {Cons, @Old::Head = h, {UnwrapRc, @Rc<New> = new} }}};
}}
#[derive(Debug,Default)]
pub struct RevCont<In>(In);
#[derive(Debug,Default)]
pub struct Rev5;
defun!{ Rev5 {
(L:List) { l:L } => {Rev5, @L = l, {}};
(Old:List, New:List) {old: Old, new:New} =>
{{If, {EmptyP, @Old}, Ret, @RevCont<Old> = RevCont(old)},
@New = new};
}}
defun!{@self (In) RevCont<In> {
(In:List, Out) { out:Out } { let (h,t) = self.0.split(); } =>
{Rev5, @In::Tail = t, {Cons, @In::Head = h, @Out = out}};
}}
mod internal { #[derive(Debug,Default)]
pub struct WrapMissing; }
defun_nocalc!{() internal::WrapMissing {
(Idx) { _:Idx } => {If, {Is, Missing, @Idx},
Missing,
There<Idx>};
}}
#[derive(Debug,Default)]
pub struct Find;
defun!{ Find {
(Needle) { _:Needle, {} } => {Ret, Missing};
(Needle, H, T) { _:Needle, { _:H; _:T} } =>
{If, {Is, Needle, @H},
Here,
{internal::WrapMissing, {Find, Needle, @T}}
};
}}
#[derive(Debug,Default)]
pub struct Any;
defun_nocalc!{() Any {
(Pred, Haystack) { _:Pred, _:Haystack }
=> {logic::Not, {Is, Missing, {FindPred, @Pred, @Haystack}}};
}}
#[derive(Debug,Default)]
pub struct Contains;
defun_nocalc!{() Contains {
(Haystack, Item) { _:Haystack, _:Item }
=> {Any, {Partial, Is, @Item}, @Haystack};
}}
#[derive(Debug,Default)]
pub struct All;
defun_nocalc!{() All {
(Pred, Haystack) {_:Pred, _:Haystack }
=> {logic::Not, {Any, {logic::Invert, Pred}, @Haystack}};
}}
#[derive(Debug,Default)]
pub struct SupersetP;
defun_nocalc!{() SupersetP {
(A,B) {a:A, b:B} => {All, {Partial, Contains, @A}, @B};
}}
#[derive(Debug,Default)]
pub struct SubsetP;
defun_nocalc!{() SubsetP {
(A,B) {a:A, b:B} => {SupersetP, @B, @A};
}}
#[derive(Debug,Default)]
pub struct FindPred;
defun_nocalc!{() FindPred {
(Pred) { _:Pred, {} } => {Ret, Missing};
(Pred, H, T) { _:Pred, { _:H; _:T }} =>
{If, {@Pred, @H},
tn::U0,
{internal::WrapMissing, {FindPred, @Pred, @T}}
};
}}
#[derive(Debug,Default)]
pub struct Concat;
defun!{ Concat {
(A:List, B:List) { a:A , b:B }
=> {{If, {EmptyP, @A}, Ret, @ConcatCont<A> = ConcatCont(a)}, @B = b};
}}
#[derive(Debug,Default)]
pub struct ConcatCont<L>(L);
defun!{@self (H,T) ConcatCont<HCons<H,T>> {
(H,T,Accum) {accum:Accum} =>
{Cons, @H = self.0.head,
{Concat, @T = self.0.tail, @Accum = accum}};
}}
#[derive(Debug,Default)]
pub struct Union;
defun!{ Union {
(A:List, B:List) { a:A, b:B }
{ let (h,t) = a.split();
let b = Rc::new(b);
}
=> { If, {EmptyP, @A},
{UnwrapRc, @Rc<B> = b.clone()},
{Union, @A::Tail = t,
{If, {Is, Missing, {Find, @A::Head, @B}},
{Cons, @A::Head = h, {UnwrapRc, @Rc<B> = b.clone()}},
{UnwrapRc, @Rc<B> = b}}}};
}}
#[derive(Debug,Default)]
pub struct Intersect;
defun!{ Intersect {
(A,B) { _:PhantomData<A>, b:B } => {Filter, {Partial, Contains, @A}, @B=b };
}}
#[derive(Debug,Default)]
pub struct Remove;
defun!{ Remove {
(A,B) { _:PhantomData<A>, b:B } =>
{Head, {Tail, {Collate, {Partial, Contains, @A}, @B=b }}};
}}
#[derive(Debug,Default)]
pub struct SetInsert;
defun!{ SetInsert {
(X: LispId, L:List) { x:X, l:L }
=> {{ If, {Is, Missing, {Find, @X, @L}},
@Prepend<X> = Prepend(x),
Ret},
@L = l};
}}
#[derive(Debug,Default)]
pub struct Prepend<T>(pub T);
defun!{ @self (X) Prepend<X> {
(X, Tail) { tail:Tail } => {Cons, @X = self.0, @Tail = tail};
}}
#[test]
fn test_reverse() {
type TestReverse = eval!{ Reverse, @{&'static str, u32, ()} };
assert_eq!( calc!{RecTest, @sexpr!{_,_,_} = sexpr_val!{4,5,6}, @u32 = 0}, 3);
assert_eq!( calc!{Reverse, @TestReverse = sexpr_val!{(), 4, "hello"}}, sexpr_val!{"hello", 4, ()});
fn rev<List>(list:List)->calc_ty!{Reverse, @List = list}
where sexpr!{Reverse, @List}: crate::engine::Calc<sexpr!{(), List}>
{
calc!{Reverse, @List = list}
}
struct A;
struct B;
rev::<_>(sexpr_val!{A,B});
}
#[cfg(test)]
macro_rules! assert_type_eq {
($a:ty, $b:ty) => { let _: ::core::marker::PhantomData<$a>=
<::core::marker::PhantomData<$b> as ::core::default::Default>::default();
}
}
#[test]
fn test_find() {
#[derive(Debug,Default,Clone)] struct A;
#[derive(Debug,Default,Clone)] struct B;
#[derive(Debug,Default,Clone)] struct C;
#[derive(Debug,Default,Clone)] struct D;
literal!{A; B; C; D};
assert_type_eq!{ Missing, eval!{ Find, B, @{}}};
assert_type_eq!{ Missing, eval!{ internal::WrapMissing, Missing}};
assert_type_eq!{ Here, eval!{ Find, B, @{B}}};
assert_type_eq!{ There<Here>, eval!{ Find, B, @{A,B,C}} };
assert_type_eq!{ Missing, eval!{ Find, D, @{A,B,C}} };
}
#[test]
fn test_concat() {
#[derive(Debug,Default,Eq,PartialEq)] struct A;
#[derive(Debug,Default,Eq,PartialEq)] struct B;
#[derive(Debug,Default,Eq,PartialEq)] struct C;
#[derive(Debug,Default,Eq,PartialEq)] struct D;
literal!{A; B; C; D};
assert_type_eq!{ sexpr!{A,B,C,D}, eval!{ Concat, @{A,B}, @{C,D}}};
fn concat<L1,L2>(a:L1, b:L2)-> <sexpr!{Concat, @L1, @L2} as Calc<sexpr!{(), L1, L2}>>::Result
where sexpr!{Concat, @L1, @L2}: Calc<sexpr!{(), L1, L2}> {
calc!{Concat, @L1=a, @L2=b}
}
assert_eq!(sexpr_val!{A,B,C,D}, concat(sexpr_val!{A,B}, sexpr_val!{C,D}));
}
#[test]
fn test_map() {
type Arg = sexpr!{u32, f64};
let arg:Arg = sexpr_val!{3, 7.4};
let _: sexpr!{Rc<u32>, Rc<f64>} = calc!{Map, WrapRc, @Arg = arg.clone()};
let _: sexpr!{&u32, &f64} = calc!{MapRef, Ret, @ &Arg = &arg};
}
#[test]
fn test_filter() {
#[derive(Debug,Default,Eq,PartialEq)] struct A;
#[derive(Debug,Default,Eq,PartialEq)] struct B;
#[derive(Debug,Default,Eq,PartialEq)] struct C;
#[derive(Debug,Default,Eq,PartialEq)] struct D;
#[derive(Debug,Default,Eq,PartialEq)] struct IsConsonant;
literal!{A; B; C; D};
use crate::ops::logic::Not;
defun!{ IsConsonant {
(T) { _:T } => {Not, {Is, @T, @A}};
}}
assert_type_eq!(sexpr!{B,C,D}, eval!{Filter, IsConsonant, @sexpr!{A,B,C,D}});
assert_type_eq!(sexpr!{B,C,D}, eval!{Filter, IsConsonant, @sexpr!{B,C,A,D}});
let _: sexpr!{B,C,D} = calc!{Filter, IsConsonant, @sexpr!{A,B,C,D} = sexpr_val!{A,B,C,D}};
let _: sexpr!{B,C,D} = calc!{Filter, IsConsonant, @sexpr!{B,C,A,D} = sexpr_val!{B,C,A,D}};
}
#[test]
fn test_any_all() {
#[derive(Debug,Default,Eq,PartialEq)] struct A;
#[derive(Debug,Default,Eq,PartialEq)] struct B;
#[derive(Debug,Default,Eq,PartialEq)] struct C;
#[derive(Debug,Default,Eq,PartialEq)] struct D;
#[derive(Debug,Default,Eq,PartialEq)] struct IsConsonant;
literal!{A; B; C; D};
use crate::ops::logic::Not;
defun!{ IsConsonant {
(T) { _:T } => {Not, {Is, @T, @A}};
}}
assert_type_eq!(tn::True, eval!{Any, IsConsonant, @sexpr!{A,B,C,D}});
assert_type_eq!(tn::True, eval!{Any, {logic::Invert, IsConsonant}, @sexpr!{A,B,C,D}});
assert_type_eq!(tn::False, eval!{Any, IsConsonant, @sexpr!{A,A,A,A}});
assert_type_eq!(tn::False, eval!{Any, {logic::Invert, IsConsonant}, @sexpr!{B,C,D}});
assert_type_eq!(tn::False, eval!{All, IsConsonant, @sexpr!{A,B,C,D}});
assert_type_eq!(tn::False, eval!{All, {logic::Invert, IsConsonant}, @sexpr!{A,B,C,D}});
assert_type_eq!(tn::True, eval!{All, {logic::Invert, IsConsonant}, @sexpr!{A,A,A,A}});
assert_type_eq!(tn::True, eval!{Any, IsConsonant, @sexpr!{B,C,D}});
}
#[test]
fn test_without() {
#[derive(Debug,Default,Eq,PartialEq)] struct A;
#[derive(Debug,Default,Eq,PartialEq)] struct B;
#[derive(Debug,Default,Eq,PartialEq)] struct C;
#[derive(Debug,Default,Eq,PartialEq)] struct D;
literal!{A; B; C; D};
assert_type_eq!(sexpr!{B,C,D}, eval!{Without, @A, @sexpr!{A,B,C,D}});
assert_type_eq!(sexpr!{B,C,D}, eval!{Without, @A, @sexpr!{B,C,A,D}});
let _: sexpr!{B,C,D} = calc!{Without, {Phantom, @A}, @sexpr!{A,B,C,D} = sexpr_val!{A,B,C,D}};
let _: sexpr!{B,C,D} = calc!{Without, {Phantom, @A}, @sexpr!{B,C,A,D} = sexpr_val!{B,C,A,D}};
}
#[test]
fn test_collate_and_any() {
#[derive(Debug,Default,Eq,PartialEq)] struct A(u32);
#[derive(Debug,Default,Eq,PartialEq)] struct B;
#[derive(Debug,Default,Eq,PartialEq)] struct C;
literal!{A; B; C};
use crate::ops::Partial;
assert_type_eq!(sexpr!{{A,A}, {B,C}}, eval!{Collate, {Phantom, {Partial, Is, @A}}, @sexpr!{A,B,A,C}});
let orig = sexpr_val!{A(1),B,A(2),C};
let (a,not_a) = CollatedBy::<partial!{Is, @A}>::collate(orig);
assert_eq!(a, sexpr_val!{A(1), A(2)});
assert_eq!(not_a, sexpr_val!{B,C});
assert_type_eq!(typenum::True, eval!{Any, {Partial, Is, @A}, @{B,A,C}});
assert_type_eq!(typenum::False, eval!{Any, {Partial, Is, @A}, @{B,B,C}});
}
#[test]
fn test_contains() {
#[derive(Debug,Default,Eq,PartialEq)] struct A;
#[derive(Debug,Default,Eq,PartialEq)] struct B;
#[derive(Debug,Default,Eq,PartialEq)] struct C;
literal!{A; B; C};
use crate::ops::Partial;
assert_type_eq!(typenum::True, eval!{Contains, @{A,B,A,C}, A});
assert_type_eq!(typenum::False, eval!{Contains, @{A,A,A,C}, B});
assert_type_eq!(typenum::True, eval!{All, {Partial, Contains, @{A,B,A,C}}, @{A,B}});
assert_type_eq!(typenum::False, eval!{All, {Partial, Contains, @{A,A,A,C}}, @{A,B}});
assert_type_eq!(typenum::True, eval!{SupersetP, @{A,B,A,C}, @{A,B}});
assert_type_eq!(typenum::False, eval!{SubsetP, @{A,B,A,C}, @{A,B}});
assert_type_eq!(typenum::True, eval!{SubsetP, @{A,B}, @{A,B,A,C}});
assert_type_eq!(typenum::False, eval!{SupersetP, @{A,B}, @{A,C}});
}
#[test]
fn test_union() {
#[derive(Debug,Default,Eq,PartialEq)] struct A;
#[derive(Debug,Default,Eq,PartialEq)] struct B;
#[derive(Debug,Default,Eq,PartialEq)] struct C;
literal!{A; B; C};
use tn::Unsigned;
assert_eq!{3, <eval!{Union, @sexpr!{A,B}, @sexpr!{A,C}} as List>::LEN};
assert_eq!{2, <eval!{Union, @sexpr!{A,B}, @sexpr!{B,A}} as List>::LEN};
assert_eq!{2, <eval!{Union, @sexpr!{A,B}, @sexpr!{ }} as List>::LEN};
assert_eq!{2, <eval!{Union, @sexpr!{ }, @sexpr!{B,A}} as List>::LEN};
assert_eq!{2, <eval!{Union, @sexpr!{C }, @sexpr!{A }} as List>::LEN};
assert_eq!{0, <eval!{Union, @sexpr!{ }, @sexpr!{ }} as List>::LEN};
let _:sexpr!{_,_,_} = calc!{Union, {BuildList, A, B}, {BuildList, A, C}};
let _:sexpr!{A,B} = calc!{Union, {BuildList, A}, {BuildList, B}};
let _:sexpr!{A,B} = calc!{Union, {BuildList}, {BuildList, A, B}};
}
#[test]
fn test_intersection() {
#[derive(Debug,Default,Eq,PartialEq)] struct A;
#[derive(Debug,Default,Eq,PartialEq)] struct B;
#[derive(Debug,Default,Eq,PartialEq)] struct C;
literal!{A; B; C};
use tn::Unsigned;
assert_eq!{1, <eval!{Intersect, {Phantom, @{A,B}}, @{A,C}} as List>::LEN};
assert_eq!{2, <eval!{Intersect, {Phantom, @{A,B}}, @{B,A}} as List>::LEN};
assert_eq!{0, <eval!{Intersect, {Phantom, @{A,B}}, @{ }} as List>::LEN};
assert_eq!{0, <eval!{Intersect, {Phantom, @{ }}, @{B,A}} as List>::LEN};
assert_eq!{0, <eval!{Intersect, {Phantom, @{C }}, @{A }} as List>::LEN};
assert_eq!{0, <eval!{Intersect, {Phantom, @{ }}, @{ }} as List>::LEN};
let _:sexpr!{A} = calc!{Intersect, {Phantom, @{A, B}}, {BuildList, A, C}};
let _:sexpr!{A,B} = calc!{Intersect, {Phantom, @{A, B}}, {BuildList, A, B}};
let _:sexpr!{A,B} = calc!{Intersect, {Phantom, @{B, A}}, {BuildList, A, B}};
}
#[test]
fn test_remove() {
#[derive(Debug,Default,Eq,PartialEq)] struct A;
#[derive(Debug,Default,Eq,PartialEq)] struct B;
#[derive(Debug,Default,Eq,PartialEq)] struct C;
literal!{A; B; C};
use tn::Unsigned;
assert_eq!{1, <eval!{Remove, {Phantom, @{A,B}}, @{A,C}} as List>::LEN};
assert_eq!{0, <eval!{Remove, {Phantom, @{A,B}}, @{B,A}} as List>::LEN};
assert_eq!{0, <eval!{Remove, {Phantom, @{A,B}}, @{ }} as List>::LEN};
assert_eq!{2, <eval!{Remove, {Phantom, @{ }}, @{B,A}} as List>::LEN};
assert_eq!{1, <eval!{Remove, {Phantom, @{C }}, @{A }} as List>::LEN};
assert_eq!{0, <eval!{Remove, {Phantom, @{ }}, @{ }} as List>::LEN};
let _:sexpr!{C} = calc!{Remove, {Phantom, @{A, B}}, {BuildList, A, C}};
let _:sexpr!{} = calc!{Remove, {Phantom, @{A, B}}, {BuildList, A, B}};
let _:sexpr!{} = calc!{Remove, {Phantom, @{B, A}}, {BuildList, A, B}};
}
#[test]
fn test_set_insert() {
#[derive(Debug,Default,Eq,PartialEq)] struct A;
#[derive(Debug,Default,Eq,PartialEq)] struct B;
#[derive(Debug,Default,Eq,PartialEq)] struct C;
literal!{A; B; C};
use tn::Unsigned;
assert_eq!{2, <eval!{SetInsert, @A, @sexpr!{A,C}} as List>::LEN};
assert_eq!{2, <eval!{SetInsert, @A, @sexpr!{B,A}} as List>::LEN};
assert_eq!{3, <eval!{SetInsert, @A, @sexpr!{B,C}} as List>::LEN};
let _:sexpr!{A,B,C} = calc!{SetInsert, @A = A, {BuildList, B, C}};
let _:sexpr!{B,C} = calc!{SetInsert, @B = B, {BuildList, B, C}};
}
#[test]
fn test_map_iter() {
#[derive(Debug,Default)] struct Double;
defun!{ Double {
(T:Copy) { x:T } => {arith::Add, @T=x, @T=x};
}}
assert_eq!(6, calc!{Double, @u32=3});
let init: Vec<u32> = vec![3,5,7];
let result: Vec<_> = MapIter::<Double,_>::new(init.into_iter()).collect();
assert_eq!(vec![6,10,14], result);
}
#[test]
fn test_fold() {
assert_type_eq!{tn::U10, eval!{FoldL, arith::Add, tn::U0, @{tn::U1, tn::U2, tn::U3, tn::U4}}};
assert_type_eq!{tn::U10, eval!{FoldR, arith::Add, @{tn::U1, tn::U2, tn::U3, tn::U4}, tn::U0}};
assert_eq!{10, calc!{FoldL, arith::Add, @u32=0, {BuildList, @u32=1, @u32=2, @u32=3, @u32=4}}};
assert_eq!{10, calc!{FoldR, arith::Add, {BuildList, @u32=1, @u32=2, @u32=3, @u32=4}, @u32=0}};
#[derive(Debug,Default)] struct Count;
defun!{ Count {
(X, Y, Z) { x:X, y:Y, _:Z } => {arith::Add, @X=x, @Y=y};
}};
assert_type_eq!{tn::U4, eval!{FoldL, {Partial, Count, @tn::U1}, @tn::U0, {BuildList, @u32=1, @u32=2, @u32=3, @u32=4}}};
}
#[test]
fn test_differ() {
#[derive(Debug,Default,Eq,PartialEq)] struct A;
#[derive(Debug,Default,Eq,PartialEq)] struct B;
#[derive(Debug,Default,Eq,PartialEq)] struct C;
#[derive(Debug,Default,Eq,PartialEq)] struct D;
literal!{A; B; C; D};
use tn::{True,False};
assert_type_eq!{False, eval!{DifferP, @{}, @{}}};
assert_type_eq!{False, eval!{DifferP, @{A}, @{A}}};
assert_type_eq!{False, eval!{DifferP, @{A, B, C}, @{A, B, C}}};
assert_type_eq!{True, eval!{DifferP, @{A, D, C}, @{A, B, C}}};
assert_type_eq!{True, eval!{DifferP, @{A}, @{A, B}}};
assert_type_eq!{True, eval!{DifferP, @{B}, @{A, B}}};
assert_type_eq!{True, eval!{DifferP, @{A, B}, @{A}}};
assert_type_eq!{True, eval!{DifferP, @{A, B}, @{B}}};
}