new test sample

This commit is contained in:
AF 2023-03-11 23:16:22 +00:00
parent 445fa00165
commit a76b29abb9
9 changed files with 212 additions and 77 deletions

View File

@ -1,8 +1,9 @@
pub mod classes;
#[cfg(test)]
pub mod tests;
pub mod copy_func;
#[cfg(test)]
pub mod test_suite;
#[cfg(test)]
pub mod tests;
pub trait WeakFunctor {
type F<'a, A>;
@ -73,4 +74,3 @@ pub trait Monad: Applicative {
Self::bind(ffa, |fa| fa)
}
}

View File

@ -1,2 +1,3 @@
pub mod optionclass;
pub mod futureclass;
pub mod soloclass;

View File

@ -1,7 +1,5 @@
use std::{future::Future, pin::Pin};
// use futures::FutureExt;
use futures::join;
use crate::func::*;
@ -56,28 +54,26 @@ impl Applicative for FutureClass {
}
fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> {
Box::pin(async {
join!(fa, fb).1
})
Box::pin(async { join!(fa, fb).1 })
}
fn discard_second<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, A> {
Box::pin(async {
join!(fa, fb).0
})
Box::pin(async { join!(fa, fb).0 })
}
}
impl Monad for FutureClass {
fn bind<'a, A: 'a, B: 'a, F: 'a + FnOnce(A) -> Self::F<'a, B>>(fa: Self::F<'a, A>, f: F) -> Self::F<'a, B> {
Box::pin(async{
f(fa.await).await
})
fn bind<'a, A: 'a, B: 'a, F: 'a + FnOnce(A) -> Self::F<'a, B>>(
fa: Self::F<'a, A>,
f: F,
) -> Self::F<'a, B> {
Box::pin(async { f(fa.await).await })
}
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> where Self::F<'a, A>: 'a {
Box::pin(async{
ffa.await.await
})
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A>
where
Self::F<'a, A>: 'a,
{
Box::pin(async { ffa.await.await })
}
}

View File

@ -3,7 +3,7 @@ use crate::func::*;
pub struct OptionClass;
impl WeakFunctor for OptionClass {
type F<'_a, A> = Option<A>;
type F<'a, A> = Option<A>;
}
impl Functor for OptionClass {
@ -106,8 +106,12 @@ mod option_tests {
}
impl test_suite::FunctorTestSuite for T {
fn sample<'a, A>() -> Vec<Box<dyn Fn(A) -> Self::F<'a, A>>> {
vec![Box::new(|_| None), Box::new(|a| Some(a))]
fn sample<'a, A: 'a, F: FnMut(&'a dyn Fn(A) -> Self::F<'a, A>)>(mut f: F)
where
Self::F<'a, A>: 'a,
{
f(&|_| None);
f(&|a| Some(a));
}
}

View File

@ -0,0 +1,74 @@
use crate::func::*;
pub struct SoloClass;
impl WeakFunctor for SoloClass {
type F<'a, A> = A;
}
impl Functor for SoloClass {
fn fmap<'a, A: 'a, B: 'a, F: 'a + FnOnce(A) -> B>(f: F, fa: Self::F<'a, A>) -> Self::F<'a, B> {
f(fa)
}
fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> {
drop(fa);
b
}
fn void<'a, A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()> {
drop(fa);
()
}
}
impl ApplicativeSeq for SoloClass {
fn seq<'a, A: 'a, B: 'a, F: 'a + FnOnce(A) -> B>(
ff: Self::F<'a, F>,
fa: Self::F<'a, A>,
) -> Self::F<'a, B> {
ff(fa)
}
}
impl ApplicativeLA2 for SoloClass {
fn la2<'a, A: 'a, B: 'a, C: 'a, F: 'a + FnOnce(A, B) -> C>(
f: F,
fa: Self::F<'a, A>,
fb: Self::F<'a, B>,
) -> Self::F<'a, C> {
f(fa, fb)
}
}
impl Applicative for SoloClass {
fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> {
a
}
fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> {
drop(fa);
fb
}
fn discard_second<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, A> {
drop(fb);
fa
}
}
impl Monad for SoloClass {
fn bind<'a, A: 'a, B: 'a, F: 'a + FnOnce(A) -> Self::F<'a, B>>(
fa: Self::F<'a, A>,
f: F,
) -> Self::F<'a, B> {
f(fa)
}
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A>
where
Self::F<'a, A>: 'a,
{
ffa
}
}

View File

@ -1,4 +1,4 @@
use super::func::*;
use crate::func::*;
pub trait CopyWeakFunctor {
type CF<'a, A: Copy>;

View File

@ -1,88 +1,85 @@
use std::rc::Rc;
use super::{tests::*, *};
pub trait FunctorTestSuite: WeakFunctor + Eqr {
fn sample<'a, A>() -> Vec<Box<dyn 'a + Fn(A) -> Self::F<'a, A>>>;
pub trait FunctorTestSuite: WeakFunctor + Eqr + 'static {
fn sample<'a, A: 'a, F: FnMut(&'a dyn Fn(A) -> Self::F<'a, A>)>(f: F)
where
Self::F<'a, A>: 'a;
}
pub fn functor_follows_laws<T: Functor + FunctorTestSuite>() -> R {
let mut res = R::default();
for pa in T::sample::<_>() {
T::sample(|pa| {
res += fmap_respects_identity::<T, _, _>(|| pa(2));
}
for pa in T::sample::<_>() {
});
T::sample(|pa| {
res += fmap_respects_composition::<T, _, _, _, _, _, _>(|x| x + 5, |x| x + 3, || pa(2));
}
});
res
}
pub fn applicative_follows_laws<T: Applicative + FunctorTestSuite>() -> R {
let mut res = functor_follows_laws::<T>();
for pa in T::sample::<_>() {
T::sample(|pa| {
res += seq_respects_identity::<T, _, _>(|| pa(2));
}
for pa in T::sample::<_>() {
for pg in T::sample::<_>() {
for pf in T::sample::<_>() {
});
T::sample(|pa| {
T::sample(|pg| {
T::sample(|pf| {
res += seq_respects_composition::<T, _, _, _, _, _, _, _, _>(
|| pf(|x| x + 5),
|| pg(|x| x + 3),
|| pa(2),
);
}
}
}
})
})
});
res += seq_is_homomorphic::<T, _, _, _, _>(|x| x + 3, || 2);
for pf in T::sample::<_>() {
T::sample(|pf| {
res += seq_respects_interchange::<T, _, _, _, _, _>(|| pf(|x| x + 3), || 2);
}
for pa in T::sample::<_>() {
for pf in T::sample::<_>() {
});
T::sample(|pa| {
T::sample(|pf| {
res += seq_can_be_expressed_via_la2::<T, _, _, _, _, _>(|| pf(|x| x + 3), || pa(2));
}
}
for pa in T::sample::<_>() {
})
});
T::sample(|pa| {
res += fmap_can_be_expressed_via_seq::<T, _, _, _, _>(|x| x + 3, || pa(2));
}
for pa in T::sample::<_>() {
for pb in T::sample::<_>() {
});
T::sample(|pa| {
T::sample(|pb| {
res += discard_can_be_expressed_via_seq_or_la2::<T, _, _, _, _>(|| pa(2), || pb(2));
}
}
})
});
res
}
pub fn monad_follows_laws<T: Monad + FunctorTestSuite>() -> R
where {
let mut res = applicative_follows_laws::<T>();
for pa in T::sample::<_>() {
res += bind_respects_left_identity::<T, _, _, _, _>(move |x| pa(x + 3), || 2);
}
for pa in T::sample::<_>() {
res += bind_respects_right_identity::<T, _, _>(move || pa(2));
}
for pa in T::sample::<_>() {
for pg in T::sample::<_>() {
let pgrc = Rc::new(pg);
for pf in T::sample::<_>() {
let pgrci = pgrc.clone();
let pfrc = Rc::new(pf);
T::sample(|pa| {
res += bind_respects_left_identity::<T, _, _, _, _>(|x| pa(x + 3), || 2);
});
T::sample(|pa| {
res += bind_respects_right_identity::<T, _, _>(|| pa(2));
});
T::sample(|pa| {
T::sample(|pg| {
T::sample(|pf| {
res += bind_is_associative::<T, _, _, _, _, _, _>(
move |x| pfrc(x + 5),
move |x| pgrci(x + 3),
|x| pf(x + 5),
|x| pg(x + 3),
|| pa(2),
);
}
}
}
for pf in T::sample::<_>() {
for pa in T::sample::<_>() {
seq_can_be_expressed_via_bind::<T, _, _, _, _, _>(|| pf(|x| x + 3), move || pa(2));
}
}
for pa in T::sample::<_>() {
res += fmap_can_be_expressed_via_bind::<T, _, _, _, _>(|x| x + 3, move || pa(2));
}
})
})
});
T::sample(|pa| {
T::sample(|pf| {
seq_can_be_expressed_via_bind::<T, _, _, _, _, _>(|| pf(|x| x + 3), || pa(2));
})
});
T::sample(|pa| {
res += fmap_can_be_expressed_via_bind::<T, _, _, _, _>(|x| x + 3, || pa(2));
});
res
}

View File

@ -1,3 +1,3 @@
pub mod copy_func;
pub mod core;
pub mod func;
mod xrcs;

63
src/xrcs.rs Normal file
View File

@ -0,0 +1,63 @@
/// Solutions to some exercises by Alisa Feistel.
/// Included here for their relevance to the whole Monad theme.
#[cfg(test)]
mod tests {
fn bind<T, F: FnOnce(T) -> Option<T>>(f: F, fa: Option<T>) -> Option<T> {
match fa {
Some(a) => f(a),
None => None,
}
}
#[test]
fn test() {
assert_eq!(bind(|x: i32| Some(x + 3), Some(2)), Some(5));
assert_eq!(bind(|x: i32| Some(x + 3), None), None);
assert_eq!(bind(|_: i32| None, Some(2)), None);
assert_eq!(bind(|_: i32| None, None), None);
assert_eq!(bind(|x: &str| Some(x), Some("apple")), Some("apple"));
assert_eq!(
bind(|_: &str| Some("banana"), Some("apple")),
Some("banana")
);
let banana = "banana".to_string();
assert_eq!(
bind(|_: &str| Some(banana.as_str()), Some("apple")),
Some("banana")
);
let banana = "banana".to_string();
assert_eq!(
bind(|_: String| Some(banana), Some("apple".to_string())),
Some("banana".to_string())
);
}
}
#[cfg(test)]
mod reftests {
fn refbind<'a, 'b, T: 'a + ?Sized, F: 'a + Fn(&'a T) -> Option<&'b T>>(
f: F,
fa: Option<&'a T>,
) -> Option<&'b T> {
match fa {
Some(a) => f(a),
None => None,
}
}
#[test]
fn test() {
let apple = "apple".to_string();
let banana = "banana".to_string();
assert_eq!(
refbind(|_: &String| Some(&banana), Some(&apple)),
Some(&banana)
);
let banana = "banana";
assert_eq!(refbind(|_: &str| Some(banana), Some("apple")), Some(banana));
}
}