new test sample
This commit is contained in:
parent
445fa00165
commit
a76b29abb9
@ -1,8 +1,9 @@
|
|||||||
pub mod classes;
|
pub mod classes;
|
||||||
#[cfg(test)]
|
pub mod copy_func;
|
||||||
pub mod tests;
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod test_suite;
|
pub mod test_suite;
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod tests;
|
||||||
|
|
||||||
pub trait WeakFunctor {
|
pub trait WeakFunctor {
|
||||||
type F<'a, A>;
|
type F<'a, A>;
|
||||||
@ -73,4 +74,3 @@ pub trait Monad: Applicative {
|
|||||||
Self::bind(ffa, |fa| fa)
|
Self::bind(ffa, |fa| fa)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
pub mod optionclass;
|
pub mod optionclass;
|
||||||
pub mod futureclass;
|
pub mod futureclass;
|
||||||
|
pub mod soloclass;
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use std::{future::Future, pin::Pin};
|
use std::{future::Future, pin::Pin};
|
||||||
|
|
||||||
// use futures::FutureExt;
|
|
||||||
|
|
||||||
use futures::join;
|
use futures::join;
|
||||||
|
|
||||||
use crate::func::*;
|
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> {
|
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 {
|
Box::pin(async { join!(fa, fb).1 })
|
||||||
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> {
|
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 {
|
Box::pin(async { join!(fa, fb).0 })
|
||||||
join!(fa, fb).0
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Monad for FutureClass {
|
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> {
|
fn bind<'a, A: 'a, B: 'a, F: 'a + FnOnce(A) -> Self::F<'a, B>>(
|
||||||
Box::pin(async{
|
fa: Self::F<'a, A>,
|
||||||
f(fa.await).await
|
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 {
|
fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A>
|
||||||
Box::pin(async{
|
where
|
||||||
ffa.await.await
|
Self::F<'a, A>: 'a,
|
||||||
})
|
{
|
||||||
|
Box::pin(async { ffa.await.await })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use crate::func::*;
|
|||||||
pub struct OptionClass;
|
pub struct OptionClass;
|
||||||
|
|
||||||
impl WeakFunctor for OptionClass {
|
impl WeakFunctor for OptionClass {
|
||||||
type F<'_a, A> = Option<A>;
|
type F<'a, A> = Option<A>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Functor for OptionClass {
|
impl Functor for OptionClass {
|
||||||
@ -106,8 +106,12 @@ mod option_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl test_suite::FunctorTestSuite for T {
|
impl test_suite::FunctorTestSuite for T {
|
||||||
fn sample<'a, A>() -> Vec<Box<dyn Fn(A) -> Self::F<'a, A>>> {
|
fn sample<'a, A: 'a, F: FnMut(&'a dyn Fn(A) -> Self::F<'a, A>)>(mut f: F)
|
||||||
vec![Box::new(|_| None), Box::new(|a| Some(a))]
|
where
|
||||||
|
Self::F<'a, A>: 'a,
|
||||||
|
{
|
||||||
|
f(&|_| None);
|
||||||
|
f(&|a| Some(a));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
74
src/func/classes/soloclass.rs
Normal file
74
src/func/classes/soloclass.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
use super::func::*;
|
use crate::func::*;
|
||||||
|
|
||||||
pub trait CopyWeakFunctor {
|
pub trait CopyWeakFunctor {
|
||||||
type CF<'a, A: Copy>;
|
type CF<'a, A: Copy>;
|
@ -1,88 +1,85 @@
|
|||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use super::{tests::*, *};
|
use super::{tests::*, *};
|
||||||
|
|
||||||
pub trait FunctorTestSuite: WeakFunctor + Eqr {
|
pub trait FunctorTestSuite: WeakFunctor + Eqr + 'static {
|
||||||
fn sample<'a, A>() -> Vec<Box<dyn 'a + Fn(A) -> Self::F<'a, A>>>;
|
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 {
|
pub fn functor_follows_laws<T: Functor + FunctorTestSuite>() -> R {
|
||||||
let mut res = R::default();
|
let mut res = R::default();
|
||||||
for pa in T::sample::<_>() {
|
T::sample(|pa| {
|
||||||
res += fmap_respects_identity::<T, _, _>(|| pa(2));
|
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 += fmap_respects_composition::<T, _, _, _, _, _, _>(|x| x + 5, |x| x + 3, || pa(2));
|
||||||
}
|
});
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn applicative_follows_laws<T: Applicative + FunctorTestSuite>() -> R {
|
pub fn applicative_follows_laws<T: Applicative + FunctorTestSuite>() -> R {
|
||||||
let mut res = functor_follows_laws::<T>();
|
let mut res = functor_follows_laws::<T>();
|
||||||
for pa in T::sample::<_>() {
|
T::sample(|pa| {
|
||||||
res += seq_respects_identity::<T, _, _>(|| pa(2));
|
res += seq_respects_identity::<T, _, _>(|| pa(2));
|
||||||
}
|
});
|
||||||
for pa in T::sample::<_>() {
|
T::sample(|pa| {
|
||||||
for pg in T::sample::<_>() {
|
T::sample(|pg| {
|
||||||
for pf in T::sample::<_>() {
|
T::sample(|pf| {
|
||||||
res += seq_respects_composition::<T, _, _, _, _, _, _, _, _>(
|
res += seq_respects_composition::<T, _, _, _, _, _, _, _, _>(
|
||||||
|| pf(|x| x + 5),
|
|| pf(|x| x + 5),
|
||||||
|| pg(|x| x + 3),
|
|| pg(|x| x + 3),
|
||||||
|| pa(2),
|
|| pa(2),
|
||||||
);
|
);
|
||||||
}
|
})
|
||||||
}
|
})
|
||||||
}
|
});
|
||||||
res += seq_is_homomorphic::<T, _, _, _, _>(|x| x + 3, || 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);
|
res += seq_respects_interchange::<T, _, _, _, _, _>(|| pf(|x| x + 3), || 2);
|
||||||
}
|
});
|
||||||
for pa in T::sample::<_>() {
|
T::sample(|pa| {
|
||||||
for pf in T::sample::<_>() {
|
T::sample(|pf| {
|
||||||
res += seq_can_be_expressed_via_la2::<T, _, _, _, _, _>(|| pf(|x| x + 3), || pa(2));
|
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));
|
res += fmap_can_be_expressed_via_seq::<T, _, _, _, _>(|x| x + 3, || pa(2));
|
||||||
}
|
});
|
||||||
for pa in T::sample::<_>() {
|
T::sample(|pa| {
|
||||||
for pb in T::sample::<_>() {
|
T::sample(|pb| {
|
||||||
res += discard_can_be_expressed_via_seq_or_la2::<T, _, _, _, _>(|| pa(2), || pb(2));
|
res += discard_can_be_expressed_via_seq_or_la2::<T, _, _, _, _>(|| pa(2), || pb(2));
|
||||||
}
|
})
|
||||||
}
|
});
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn monad_follows_laws<T: Monad + FunctorTestSuite>() -> R
|
pub fn monad_follows_laws<T: Monad + FunctorTestSuite>() -> R
|
||||||
where {
|
where {
|
||||||
let mut res = applicative_follows_laws::<T>();
|
let mut res = applicative_follows_laws::<T>();
|
||||||
for pa in T::sample::<_>() {
|
T::sample(|pa| {
|
||||||
res += bind_respects_left_identity::<T, _, _, _, _>(move |x| pa(x + 3), || 2);
|
res += bind_respects_left_identity::<T, _, _, _, _>(|x| pa(x + 3), || 2);
|
||||||
}
|
});
|
||||||
for pa in T::sample::<_>() {
|
T::sample(|pa| {
|
||||||
res += bind_respects_right_identity::<T, _, _>(move || pa(2));
|
res += bind_respects_right_identity::<T, _, _>(|| pa(2));
|
||||||
}
|
});
|
||||||
for pa in T::sample::<_>() {
|
T::sample(|pa| {
|
||||||
for pg in T::sample::<_>() {
|
T::sample(|pg| {
|
||||||
let pgrc = Rc::new(pg);
|
T::sample(|pf| {
|
||||||
for pf in T::sample::<_>() {
|
|
||||||
let pgrci = pgrc.clone();
|
|
||||||
let pfrc = Rc::new(pf);
|
|
||||||
res += bind_is_associative::<T, _, _, _, _, _, _>(
|
res += bind_is_associative::<T, _, _, _, _, _, _>(
|
||||||
move |x| pfrc(x + 5),
|
|x| pf(x + 5),
|
||||||
move |x| pgrci(x + 3),
|
|x| pg(x + 3),
|
||||||
|| pa(2),
|
|| pa(2),
|
||||||
);
|
);
|
||||||
}
|
})
|
||||||
}
|
})
|
||||||
}
|
});
|
||||||
for pf in T::sample::<_>() {
|
T::sample(|pa| {
|
||||||
for pa in T::sample::<_>() {
|
T::sample(|pf| {
|
||||||
seq_can_be_expressed_via_bind::<T, _, _, _, _, _>(|| pf(|x| x + 3), move || pa(2));
|
seq_can_be_expressed_via_bind::<T, _, _, _, _, _>(|| pf(|x| x + 3), || pa(2));
|
||||||
}
|
})
|
||||||
}
|
});
|
||||||
for pa in T::sample::<_>() {
|
T::sample(|pa| {
|
||||||
res += fmap_can_be_expressed_via_bind::<T, _, _, _, _>(|x| x + 3, move || pa(2));
|
res += fmap_can_be_expressed_via_bind::<T, _, _, _, _>(|x| x + 3, || pa(2));
|
||||||
}
|
});
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
pub mod copy_func;
|
|
||||||
pub mod core;
|
pub mod core;
|
||||||
pub mod func;
|
pub mod func;
|
||||||
|
mod xrcs;
|
||||||
|
63
src/xrcs.rs
Normal file
63
src/xrcs.rs
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user