diff options
| author | Andreas Grois <andi@grois.info> | 2023-03-18 22:05:20 +0100 |
|---|---|---|
| committer | Andreas Grois <andi@grois.info> | 2023-03-18 22:05:20 +0100 |
| commit | bb7719d6d050d7bf957f0df7a78e6c74b1c9615b (patch) | |
| tree | 4fcfa39520793069357f0ec29d45f424347c3aa5 | |
| parent | 7e739c74a68b1b5adfbcb93c01ef87365946dad0 (diff) | |
First few integration tests: trivial types
| -rw-r--r-- | src/lib.rs | 12 | ||||
| -rw-r--r-- | tests/trivial.rs | 39 | ||||
| -rw-r--r-- | tests/vector.rs | 127 | ||||
| -rw-r--r-- | tests/with_lifetimes.rs | 60 |
4 files changed, 232 insertions, 6 deletions
@@ -9,9 +9,9 @@ macro_rules! free { Free(Box<$f>) } impl<$($other_lifetimes,)* $generic> $name<$($other_lifetimes,)* $generic>{ - $v fn lift_f(command : <$f as $crate::higher::Functor<Self>>::Target<$generic>) -> Self{ + $v fn lift_f(functor : <$f as $crate::higher::Functor<Self>>::Target<$generic>) -> Self{ use $crate::higher::Functor; - Self::Free(Box::new(command.fmap(|a| Self::Pure(a)))) + Self::Free(Box::new(functor.fmap(|a| Self::Pure(a)))) } $v fn retract<'free_macro_reserved_lifetime>(self) -> <$f as $crate::higher::Bind<'free_macro_reserved_lifetime,Self>>::Target<$generic> where $f : $crate::higher::Monad<'free_macro_reserved_lifetime,Self>, <$f as $crate::higher::Bind<'free_macro_reserved_lifetime,Self>>::Target<$generic> : $crate::higher::Pure<$generic> { @@ -43,7 +43,7 @@ macro_rules! free { } } - impl<'free_macro_reserved_lifetime, $($other_lifetimes,)* A> $crate::higher::Apply<'free_macro_reserved_lifetime, A> for $name<$($other_lifetimes,)* A> where A: 'free_macro_reserved_lifetime + Clone,{ + impl<'free_macro_reserved_lifetime, $($other_lifetimes,)* A> $crate::higher::Apply<'free_macro_reserved_lifetime, A> for $name<$($other_lifetimes,)* A> where A: 'free_macro_reserved_lifetime + Clone, Self : Clone { type Target<T> = $name<$($other_lifetimes,)* T> where T:'free_macro_reserved_lifetime; fn apply<B>( self, @@ -80,9 +80,9 @@ macro_rules! free { Free(Box<$f>) } impl<$($other_lifetimes : $a,)* $generic> $name<$($other_lifetimes,)* $generic> where $generic : $a { - $v fn lift_f(command : <$f as $crate::higher::Functor<$a, Self>>::Target<$generic>) -> Self{ + $v fn lift_f(functor : <$f as $crate::higher::Functor<$a, Self>>::Target<$generic>) -> Self{ use $crate::higher::Functor; - Self::Free(Box::new(command.fmap(|a| Self::Pure(a)))) + Self::Free(Box::new(functor.fmap(|a| Self::Pure(a)))) } $v fn retract(self) -> <$f as $crate::higher::Bind<$a,Self>>::Target<$generic> where $f : $crate::higher::Monad<$a,Self>, <$f as $crate::higher::Bind<$a,Self>>::Target<$generic> : $crate::higher::Pure<$generic> { @@ -118,7 +118,7 @@ macro_rules! free { } } - impl<$($other_lifetimes : $a,)* A> $crate::higher::Apply<$a, A> for $name<$($other_lifetimes,)* A> where A: $a + Clone,{ + impl<$($other_lifetimes : $a,)* A> $crate::higher::Apply<$a, A> for $name<$($other_lifetimes,)* A> where A: $a + Clone, Self : Clone{ type Target<T> = $name<$($other_lifetimes,)* T> where T:$a; fn apply<B>( self, diff --git a/tests/trivial.rs b/tests/trivial.rs new file mode 100644 index 0000000..5468fe4 --- /dev/null +++ b/tests/trivial.rs @@ -0,0 +1,39 @@ +//! A trivial test functor. Not holding any data, so this is basically just a linked list of free-nodes. +use higher_free_macro::free; +use higher::{Functor, Bind, Apply}; + +#[derive(Functor, Clone)] +struct TrivialFunctor<A>(A); + +free!(TrivialFreeMonad<A>, TrivialFunctor<TrivialFreeMonad<A>>); + +#[test] +fn test_trivial_functor() { + let m = TrivialFreeMonad::lift_f(TrivialFunctor(37u32)); + let m = m.fmap(|x| x*2); + let m = m.bind(|x| TrivialFreeMonad::Free(Box::new(TrivialFunctor(TrivialFreeMonad::Pure(x))))); + let f = TrivialFreeMonad::Pure((|x| x*3).into()); + let m = m.apply(f); + match m { + TrivialFreeMonad::Free(b) => { + match *b { + TrivialFunctor(f) => { + match f { + TrivialFreeMonad::Free(b) => { + match *b { + TrivialFunctor(f) => { + match f{ + TrivialFreeMonad::Pure(x) => assert_eq!(x, 37*6), + _ => unreachable!() + } + } + } + }, + _ => unreachable!() + } + } + } + } + _ => unreachable!() + } +}
\ No newline at end of file diff --git a/tests/vector.rs b/tests/vector.rs new file mode 100644 index 0000000..74cc913 --- /dev/null +++ b/tests/vector.rs @@ -0,0 +1,127 @@ +//! Tests if creating a Free Monad for a Vec works. Not sure if this is useful in any way. +//! It is a nice illustration that Free Monads are tree-like though. + +use higher_free_macro::free; +use higher::{Functor, Bind, Apply}; + +free!(FreeVec<A>, Vec<FreeVec<A>>); + +#[test] +fn test_vector(){ + let fv = FreeVec::lift_f(vec![2,3,4]); + let fv = fv.fmap(|x| x*2); + let fv = fv.bind(|x| if x%3 == 0 {FreeVec::Pure(x)} else {FreeVec::lift_f(vec![x,x+1])}); + let f = FreeVec::lift_f(vec![(|x| (x as f32) / 3.0) as fn(u32)->f32, (|x| (x+2) as f32) as fn(u32)->f32]); + let r = fv.apply(f.fmap(Into::into)); + match r { + FreeVec::Free(v) => { + match &**v{ + [a,b] => { + match a { + FreeVec::Free(v) => { + match &***v { + [a,b,c] => { + match a { + FreeVec::Free(v) => { + match &***v { + [a,b] => { + match a{ + FreeVec::Free(_) => unreachable!(), + FreeVec::Pure(v) => {assert_eq!(4.0f32/3.0f32, *v)} + } + match b{ + FreeVec::Free(_) => unreachable!(), + FreeVec::Pure(v) => {assert_eq!(5.0f32/3.0f32, *v)} + } + }, + _ => unreachable!() + } + } + FreeVec::Pure(_) => unreachable!(), + } + match b { + FreeVec::Free(_) => unreachable!(), + FreeVec::Pure(v) => assert_eq!(2.0f32, *v), + } + match c { + FreeVec::Free(v) => { + match &***v { + [a,b] => { + match a{ + FreeVec::Free(_) => unreachable!(), + FreeVec::Pure(v) => {assert_eq!(8.0f32/3.0f32, *v)} + } + match b{ + FreeVec::Free(_) => unreachable!(), + FreeVec::Pure(v) => {assert_eq!(3.0f32, *v)} + } + }, + _ => unreachable!() + } + } + FreeVec::Pure(_) => unreachable!(), + } + }, + _ => unreachable!() + } + } + FreeVec::Pure(_) => unreachable!() + } + + match b { + FreeVec::Free(v) => { + match &***v { + [a,b,c] => { + match a { + FreeVec::Free(v) => { + match &***v { + [a,b] => { + match a{ + FreeVec::Free(_) => unreachable!(), + FreeVec::Pure(v) => {assert_eq!(6.0f32, *v)} + } + match b{ + FreeVec::Free(_) => unreachable!(), + FreeVec::Pure(v) => {assert_eq!(7.0f32, *v)} + } + }, + _ => unreachable!() + } + } + FreeVec::Pure(_) => unreachable!(), + } + match b { + FreeVec::Free(_) => unreachable!(), + FreeVec::Pure(v) => assert_eq!(8.0f32, *v), + } + match c { + FreeVec::Free(v) => { + match &***v { + [a,b] => { + match a{ + FreeVec::Free(_) => unreachable!(), + FreeVec::Pure(v) => {assert_eq!(10.0f32, *v)} + } + match b{ + FreeVec::Free(_) => unreachable!(), + FreeVec::Pure(v) => {assert_eq!(11.0f32, *v)} + } + }, + _ => unreachable!() + } + } + FreeVec::Pure(_) => unreachable!(), + } + }, + _ => unreachable!() + } + } + FreeVec::Pure(_) => unreachable!() + } + }, + _ => unreachable!() + } + } + FreeVec::Pure(_) => unreachable!() + } +}
\ No newline at end of file diff --git a/tests/with_lifetimes.rs b/tests/with_lifetimes.rs new file mode 100644 index 0000000..2e87878 --- /dev/null +++ b/tests/with_lifetimes.rs @@ -0,0 +1,60 @@ +//! Test for the case that the Functor the Free Monad is based on has lifetime parameters that do not depend on the +//! lifetime of the mapping function in the Functor implementation. + +use higher_free_macro::free; +use higher::{Functor, Bind, Apply}; + +#[derive(Functor, Clone)] +struct WithLifetimes<'a,'b, A>{ + s1 : &'a str, + s2 : &'b str, + next : A +} + +free!(FreeWithLifetimes<'a,'b,A>, WithLifetimes<'a,'b,FreeWithLifetimes<'a,'b,A>>); + +fn lifetime_helper<'a,'b>(s1 : &'a str, s2 : &'b str) -> FreeWithLifetimes<'a, 'b, u32>{ + let fv = FreeWithLifetimes::lift_f(WithLifetimes{ s1, s2, next: 15}); + fv.fmap(|x| x+1) +} + +#[test] +fn test_with_lifetimes(){ + let s1 = "First"; + let s2 = "Second"; + let fv = lifetime_helper(s1, s2); + let s3 = "Third"; + let s4 = "Fourth"; + let fv = fv.bind(|x| FreeWithLifetimes::lift_f(WithLifetimes{ s1: s3, s2: s4, next : x+2})); + let s5 = "Fifth"; + let s6 = "Sixth"; + let fa = FreeWithLifetimes::lift_f(WithLifetimes{s1: s5, s2: s6, next : (|x| x+3).into()}); + let fv = fv.apply(fa); + match fv { + FreeWithLifetimes::Free(v) => { + assert_eq!(v.s1, s5); + assert_eq!(v.s2, s6); + match v.next { + FreeWithLifetimes::Free(v) => { + assert_eq!(v.s1, s1); + assert_eq!(v.s2, s2); + match v.next { + FreeWithLifetimes::Free(v) => { + assert_eq!(v.s1, s3); + assert_eq!(v.s2, s4); + match v.next { + FreeWithLifetimes::Free(_) => unreachable!(), + FreeWithLifetimes::Pure(a) => { + assert_eq!(a, 21); + }, + } + }, + FreeWithLifetimes::Pure(_) => unreachable!(), + } + }, + FreeWithLifetimes::Pure(_) => unreachable!(), + } + }, + FreeWithLifetimes::Pure(_) => unreachable!() + } +}
\ No newline at end of file |
