new test sample
This commit is contained in:
parent
445fa00165
commit
a76b29abb9
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,2 +1,3 @@
|
||||
pub mod optionclass;
|
||||
pub mod futureclass;
|
||||
pub mod soloclass;
|
||||
|
@ -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 })
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
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 {
|
||||
type CF<'a, A: Copy>;
|
@ -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
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
pub mod copy_func;
|
||||
pub mod core;
|
||||
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