FnOnce Monad
This commit is contained in:
parent
1872765cb6
commit
0b0914bd4e
0
src/core.rs
Normal file
0
src/core.rs
Normal file
526
src/func.rs
Normal file
526
src/func.rs
Normal file
@ -0,0 +1,526 @@
|
|||||||
|
pub trait Functor {
|
||||||
|
type F<T>;
|
||||||
|
|
||||||
|
fn fmap<A, B, F: FnOnce(A) -> B>(f: F, fa: Self::F<A>) -> Self::F<B>;
|
||||||
|
|
||||||
|
fn replace<A, B>(fa: Self::F<A>, b: B) -> Self::F<B> {
|
||||||
|
Self::fmap(|_| b, fa)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn void<A>(fa: Self::F<A>) -> Self::F<()> {
|
||||||
|
Self::replace(fa, ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ApplicativeSeq: Functor {
|
||||||
|
fn seq<A, B, F: FnOnce(A) -> B>(ff: Self::F<F>, fa: Self::F<A>) -> Self::F<B>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ApplicativeLA2: Functor {
|
||||||
|
fn la2<A, B, C, F: FnOnce(A, B) -> C>(f: F, fa: Self::F<A>, fb: Self::F<B>) -> Self::F<C>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ApplicativeSeqOnly: ApplicativeSeq {}
|
||||||
|
|
||||||
|
pub trait ApplicativeLA2Only: ApplicativeLA2 {}
|
||||||
|
|
||||||
|
impl<T: ApplicativeLA2Only> ApplicativeSeq for T {
|
||||||
|
fn seq<A, B, F: FnOnce(A) -> B>(ff: Self::F<F>, fa: Self::F<A>) -> Self::F<B> {
|
||||||
|
Self::la2(|f, a| f(a), ff, fa)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ApplicativeSeqOnly> ApplicativeLA2 for T {
|
||||||
|
fn la2<A, B, C, F: FnOnce(A, B) -> C>(f: F, fa: Self::F<A>, fb: Self::F<B>) -> Self::F<C> {
|
||||||
|
Self::seq(Self::fmap(|a| |b| f(a, b), fa), fb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Applicative: Functor + ApplicativeSeq + ApplicativeLA2 {
|
||||||
|
fn pure<A>(a: A) -> Self::F<A>;
|
||||||
|
|
||||||
|
fn discard_first<A, B>(fa: Self::F<A>, fb: Self::F<B>) -> Self::F<B> {
|
||||||
|
Self::seq(Self::replace(fa, |b| b), fb)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn discard_second<A, B>(fa: Self::F<A>, fb: Self::F<B>) -> Self::F<A> {
|
||||||
|
Self::la2(|a, _| a, fa, fb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Monad: Applicative {
|
||||||
|
fn bind<A, B, F: FnOnce(A) -> Self::F<B>>(fa: Self::F<A>, f: F) -> Self::F<B>;
|
||||||
|
|
||||||
|
fn join<A>(ffa: Self::F<Self::F<A>>) -> Self::F<A> {
|
||||||
|
Self::bind(ffa, |fa| fa)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OptionClass;
|
||||||
|
|
||||||
|
impl Functor for OptionClass {
|
||||||
|
type F<T> = Option<T>;
|
||||||
|
|
||||||
|
fn fmap<A, B, F: FnOnce(A) -> B>(f: F, fa: Self::F<A>) -> Self::F<B> {
|
||||||
|
match fa {
|
||||||
|
Some(a) => Some(f(a)),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace<A, B>(fa: Self::F<A>, b: B) -> Self::F<B> {
|
||||||
|
match fa {
|
||||||
|
Some(_) => Some(b),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApplicativeSeq for OptionClass {
|
||||||
|
fn seq<A, B, F: FnOnce(A) -> B>(ff: Self::F<F>, fa: Self::F<A>) -> Self::F<B> {
|
||||||
|
match (ff, fa) {
|
||||||
|
(Some(f), Some(a)) => Some(f(a)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApplicativeLA2 for OptionClass {
|
||||||
|
fn la2<A, B, C, F: FnOnce(A, B) -> C>(f: F, fa: Self::F<A>, fb: Self::F<B>) -> Self::F<C> {
|
||||||
|
match (fa, fb) {
|
||||||
|
(Some(a), Some(b)) => Some(f(a, b)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Applicative for OptionClass {
|
||||||
|
fn pure<A>(a: A) -> Self::F<A> {
|
||||||
|
Some(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn discard_first<A, B>(fa: Self::F<A>, fb: Self::F<B>) -> Self::F<B> {
|
||||||
|
match fa {
|
||||||
|
Some(_) => fb,
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Monad for OptionClass {
|
||||||
|
fn bind<A, B, F: FnOnce(A) -> Self::F<B>>(fa: Self::F<A>, f: F) -> Self::F<B> {
|
||||||
|
match fa {
|
||||||
|
Some(a) => f(a),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use core::fmt::Debug;
|
||||||
|
|
||||||
|
pub fn make_none<T>(_: Option<T>) -> Option<T> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fmap_respects_identity<T: Functor, A, FA0: Fn() -> T::F<A>>(fa0: FA0)
|
||||||
|
where
|
||||||
|
T::F<A>: Debug + PartialEq,
|
||||||
|
{
|
||||||
|
assert_eq!(T::fmap(|a| a, fa0()), fa0());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fmap_respects_composition<
|
||||||
|
T: Functor,
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
C,
|
||||||
|
F: Fn(B) -> C,
|
||||||
|
G: Fn(A) -> B,
|
||||||
|
FA0: Fn() -> T::F<A>,
|
||||||
|
>(
|
||||||
|
f: F,
|
||||||
|
g: G,
|
||||||
|
fa0: FA0,
|
||||||
|
) where
|
||||||
|
T::F<C>: Debug + PartialEq,
|
||||||
|
{
|
||||||
|
assert_eq!(T::fmap(|a| f(g(a)), fa0()), T::fmap(f, T::fmap(g, fa0())));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn seq_respects_identity<T: Applicative, A, FA0: Fn() -> T::F<A>>(fa0: FA0)
|
||||||
|
where
|
||||||
|
T::F<A>: Debug + PartialEq,
|
||||||
|
{
|
||||||
|
assert_eq!(T::seq(T::pure(|a| a), fa0()), fa0());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn seq_respects_composition<
|
||||||
|
T: Applicative,
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
C,
|
||||||
|
F: Fn(B) -> C,
|
||||||
|
G: Fn(A) -> B,
|
||||||
|
FF0: Fn() -> T::F<F>,
|
||||||
|
FG0: Fn() -> T::F<G>,
|
||||||
|
FA0: Fn() -> T::F<A>,
|
||||||
|
>(
|
||||||
|
ff0: FF0,
|
||||||
|
fg0: FG0,
|
||||||
|
fa0: FA0,
|
||||||
|
) where
|
||||||
|
T::F<C>: Debug + PartialEq,
|
||||||
|
{
|
||||||
|
assert_eq!(
|
||||||
|
T::seq(
|
||||||
|
T::seq(
|
||||||
|
T::seq(T::pure(|f: F| |g: G| move |a| f(g(a))), ff0()),
|
||||||
|
fg0()
|
||||||
|
),
|
||||||
|
fa0()
|
||||||
|
),
|
||||||
|
T::seq(ff0(), T::seq(fg0(), fa0()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn seq_is_homomorphic<T: Applicative, A, B, A0: Fn() -> A, F: Copy + Fn(A) -> B>(
|
||||||
|
f: F,
|
||||||
|
a0: A0,
|
||||||
|
) where
|
||||||
|
T::F<B>: Debug + PartialEq,
|
||||||
|
{
|
||||||
|
assert_eq!(T::seq(T::pure(f), T::pure(a0())), T::pure(f(a0())));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn seq_respects_interchange<
|
||||||
|
T: Applicative,
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
F: Fn(A) -> B,
|
||||||
|
A0: Fn() -> A,
|
||||||
|
FF0: Fn() -> T::F<F>,
|
||||||
|
>(
|
||||||
|
ff0: FF0,
|
||||||
|
a0: A0,
|
||||||
|
) where
|
||||||
|
T::F<B>: Debug + PartialEq,
|
||||||
|
{
|
||||||
|
assert_eq!(
|
||||||
|
T::seq(ff0(), T::pure(a0())),
|
||||||
|
T::seq(T::pure(|f: F| f(a0())), ff0())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn seq_can_be_expressed_via_la2<
|
||||||
|
T: Applicative,
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
F: Fn(A) -> B,
|
||||||
|
FA0: Fn() -> T::F<A>,
|
||||||
|
FF0: Fn() -> T::F<F>,
|
||||||
|
>(
|
||||||
|
ff0: FF0,
|
||||||
|
fa0: FA0,
|
||||||
|
) where
|
||||||
|
T::F<B>: Debug + PartialEq,
|
||||||
|
{
|
||||||
|
assert_eq!(T::seq(ff0(), fa0()), T::la2(|f, a| f(a), ff0(), fa0()));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fmap_can_be_expressed_via_seq<
|
||||||
|
T: Applicative,
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
F: Copy + Fn(A) -> B,
|
||||||
|
FA0: Fn() -> T::F<A>,
|
||||||
|
>(
|
||||||
|
f: F,
|
||||||
|
fa0: FA0,
|
||||||
|
) where
|
||||||
|
T::F<B>: Debug + PartialEq,
|
||||||
|
{
|
||||||
|
assert_eq!(T::fmap(f, fa0()), T::seq(T::pure(f), fa0()));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn discard_can_be_expressed_via_seq_or_la2<
|
||||||
|
T: Applicative,
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
FA0: Fn() -> T::F<A>,
|
||||||
|
FB0: Fn() -> T::F<B>,
|
||||||
|
>(
|
||||||
|
fa0: FA0,
|
||||||
|
fb0: FB0,
|
||||||
|
) where
|
||||||
|
T::F<B>: Debug + PartialEq,
|
||||||
|
{
|
||||||
|
assert_eq!(
|
||||||
|
T::discard_first(fa0(), fb0()),
|
||||||
|
T::seq(T::replace(fa0(), |b| b), fb0())
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
T::discard_second(fb0(), fa0()),
|
||||||
|
T::la2(|b, _| b, fb0(), fa0())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind_respects_left_identity<T: Monad, A, B, F: Copy + Fn(A) -> T::F<B>, A0: Fn() -> A>(
|
||||||
|
f: F,
|
||||||
|
a0: A0,
|
||||||
|
) where
|
||||||
|
T::F<B>: Debug + PartialEq,
|
||||||
|
{
|
||||||
|
assert_eq!(T::bind(T::pure(a0()), f), f(a0()));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind_respects_right_identity<T: Monad, A, FA0: Fn() -> T::F<A>>(fa0: FA0)
|
||||||
|
where
|
||||||
|
T::F<A>: Debug + PartialEq,
|
||||||
|
{
|
||||||
|
assert_eq!(T::bind(fa0(), T::pure), fa0());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind_is_associative<
|
||||||
|
T: Monad,
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
C,
|
||||||
|
F: Copy + Fn(B) -> T::F<C>,
|
||||||
|
G: Copy + Fn(A) -> T::F<B>,
|
||||||
|
FA0: Fn() -> T::F<A>,
|
||||||
|
>(
|
||||||
|
f: F,
|
||||||
|
g: G,
|
||||||
|
fa0: FA0,
|
||||||
|
) where
|
||||||
|
T::F<C>: Debug + PartialEq,
|
||||||
|
{
|
||||||
|
assert_eq!(
|
||||||
|
T::bind(fa0(), |a| T::bind(g(a), f)),
|
||||||
|
T::bind(T::bind(fa0(), g), f)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn seq_can_be_expressed_via_bind<
|
||||||
|
T: Monad,
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
F: Fn(A) -> B,
|
||||||
|
FA0: Fn() -> T::F<A>,
|
||||||
|
FF0: Fn() -> T::F<F>,
|
||||||
|
>(
|
||||||
|
ff0: FF0,
|
||||||
|
fa0: FA0,
|
||||||
|
) where
|
||||||
|
T::F<B>: Debug + PartialEq,
|
||||||
|
{
|
||||||
|
assert_eq!(
|
||||||
|
T::seq(ff0(), fa0()),
|
||||||
|
T::bind(ff0(), |f| T::bind(fa0(), |a| T::pure(f(a))))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fmap_can_be_expressed_via_bind<
|
||||||
|
T: Monad,
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
F: Copy + Fn(A) -> B,
|
||||||
|
FA0: Fn() -> T::F<A>,
|
||||||
|
>(
|
||||||
|
f: F,
|
||||||
|
fa0: FA0,
|
||||||
|
) where
|
||||||
|
T::F<B>: Debug + PartialEq,
|
||||||
|
{
|
||||||
|
assert_eq!(T::fmap(f, fa0()), T::bind(fa0(), |a| T::pure(f(a))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod option_tests {
|
||||||
|
use crate::func::tests;
|
||||||
|
|
||||||
|
use super::{tests::make_none, Functor, OptionClass as T};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fmap_f_none_is_none() {
|
||||||
|
assert_eq!(T::fmap(|_: ()| (), None), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fmap_f_some_a_is_some_f_a() {
|
||||||
|
assert_eq!(T::fmap(|x| x * x, Some(2)), Some(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fmap_respects_identity() {
|
||||||
|
tests::fmap_respects_identity::<T, _, _>(|| None::<i32>);
|
||||||
|
tests::fmap_respects_identity::<T, _, _>(|| Some(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fmap_respects_composition() {
|
||||||
|
tests::fmap_respects_composition::<T, _, _, _, _, _, _>(
|
||||||
|
|x| x + 5,
|
||||||
|
|x| x + 3,
|
||||||
|
|| None::<i32>,
|
||||||
|
);
|
||||||
|
tests::fmap_respects_composition::<T, _, _, _, _, _, _>(|x| x + 5, |x| x + 3, || Some(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn replace_none_b_is_none() {
|
||||||
|
assert_eq!(T::replace(None::<i32>, 1), None);
|
||||||
|
assert_eq!(T::void(None::<i32>), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn replace_some_a_b_is_some_b() {
|
||||||
|
assert_eq!(T::replace(Some(1), 2), Some(2));
|
||||||
|
assert_eq!(T::void(Some(1)), Some(()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn seq_respects_identity() {
|
||||||
|
tests::seq_respects_identity::<T, _, _>(|| None::<i32>);
|
||||||
|
tests::seq_respects_identity::<T, _, _>(|| Some(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn seq_respects_composition() {
|
||||||
|
tests::seq_respects_composition::<T, _, _, _, _, _, _, _, _>(
|
||||||
|
|| Some(|x| x + 5),
|
||||||
|
|| Some(|x| x + 3),
|
||||||
|
|| Some(2),
|
||||||
|
);
|
||||||
|
tests::seq_respects_composition::<T, _, _, _, _, _, _, _, _>(
|
||||||
|
|| tests::make_none(Some(|x| x + 5)),
|
||||||
|
|| Some(|x| x + 3),
|
||||||
|
|| Some(2),
|
||||||
|
);
|
||||||
|
tests::seq_respects_composition::<T, _, _, _, _, _, _, _, _>(
|
||||||
|
|| Some(|x| x + 5),
|
||||||
|
|| tests::make_none(Some(|x| x + 3)),
|
||||||
|
|| Some(2),
|
||||||
|
);
|
||||||
|
tests::seq_respects_composition::<T, _, _, _, _, _, _, _, _>(
|
||||||
|
|| Some(|x| x + 5),
|
||||||
|
|| Some(|x| x + 3),
|
||||||
|
|| None::<i32>,
|
||||||
|
);
|
||||||
|
tests::seq_respects_composition::<T, _, _, _, _, _, _, _, _>(
|
||||||
|
|| tests::make_none(Some(|x| x + 5)),
|
||||||
|
|| tests::make_none(Some(|x| x + 3)),
|
||||||
|
|| None::<i32>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn seq_is_homomorphic() {
|
||||||
|
tests::seq_is_homomorphic::<T, _, _, _, _>(|x| x + 3, || 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn seq_respects_interchange() {
|
||||||
|
tests::seq_respects_interchange::<T, _, _, _, _, _>(|| Some(|x| x + 3), || 2);
|
||||||
|
tests::seq_respects_interchange::<T, _, _, _, _, _>(|| make_none(Some(|x| x + 3)), || 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn seq_can_be_expressed_via_la2() {
|
||||||
|
tests::seq_can_be_expressed_via_la2::<T, _, _, _, _, _>(|| Some(|x| x + 3), || Some(2));
|
||||||
|
tests::seq_can_be_expressed_via_la2::<T, _, _, _, _, _>(
|
||||||
|
|| make_none(Some(|x| x + 3)),
|
||||||
|
|| Some(2),
|
||||||
|
);
|
||||||
|
tests::seq_can_be_expressed_via_la2::<T, _, _, _, _, _>(|| Some(|x| x + 3), || None::<i32>);
|
||||||
|
tests::seq_can_be_expressed_via_la2::<T, _, _, _, _, _>(
|
||||||
|
|| make_none(Some(|x| x + 3)),
|
||||||
|
|| None::<i32>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fmap_can_be_expressed_via_seq() {
|
||||||
|
tests::fmap_can_be_expressed_via_seq::<T, _, _, _, _>(|x| x + 3, || Some(2));
|
||||||
|
tests::fmap_can_be_expressed_via_seq::<T, _, _, _, _>(|x| x + 3, || None::<i32>);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn discard_can_be_expressed_via_seq_or_la2() {
|
||||||
|
tests::discard_can_be_expressed_via_seq_or_la2::<T, _, _, _, _>(|| Some(2), || Some(3));
|
||||||
|
tests::discard_can_be_expressed_via_seq_or_la2::<T, _, _, _, _>(|| Some(2), || None::<i32>);
|
||||||
|
tests::discard_can_be_expressed_via_seq_or_la2::<T, _, _, _, _>(|| None::<i32>, || Some(3));
|
||||||
|
tests::discard_can_be_expressed_via_seq_or_la2::<T, _, _, _, _>(
|
||||||
|
|| None::<i32>,
|
||||||
|
|| None::<i32>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bind_respects_left_identity() {
|
||||||
|
tests::bind_respects_left_identity::<T, _, _, _, _>(|x| Some(x + 3), || 2);
|
||||||
|
tests::bind_respects_left_identity::<T, _, _, _, _>(|_| None::<i32>, || 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bind_respects_right_identity() {
|
||||||
|
tests::bind_respects_right_identity::<T, _, _>(|| Some(1));
|
||||||
|
tests::bind_respects_right_identity::<T, _, _>(|| None::<i32>);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bind_is_associative() {
|
||||||
|
tests::bind_is_associative::<T, _, _, _, _, _, _>(
|
||||||
|
|x| Some(x + 5),
|
||||||
|
|x| Some(x + 3),
|
||||||
|
|| Some(2),
|
||||||
|
);
|
||||||
|
tests::bind_is_associative::<T, _, _, _, _, _, _>(
|
||||||
|
|_| None::<i32>,
|
||||||
|
|x| Some(x + 3),
|
||||||
|
|| Some(2),
|
||||||
|
);
|
||||||
|
tests::bind_is_associative::<T, _, _, _, _, _, _>(
|
||||||
|
|x| Some(x + 5),
|
||||||
|
|_| None::<i32>,
|
||||||
|
|| Some(2),
|
||||||
|
);
|
||||||
|
tests::bind_is_associative::<T, _, _, _, _, _, _>(
|
||||||
|
|x| Some(x + 5),
|
||||||
|
|x| Some(x + 3),
|
||||||
|
|| None::<i32>,
|
||||||
|
);
|
||||||
|
tests::bind_is_associative::<T, _, _, _, _, _, _>(
|
||||||
|
|_| None::<i32>,
|
||||||
|
|_| None::<i32>,
|
||||||
|
|| None::<i32>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn seq_can_be_expressed_via_bind() {
|
||||||
|
tests::seq_can_be_expressed_via_bind::<T, _, _, _, _, _>(|| Some(|x| x + 3), || Some(2));
|
||||||
|
tests::seq_can_be_expressed_via_bind::<T, _, _, _, _, _>(
|
||||||
|
|| Some(|x| x + 3),
|
||||||
|
|| None::<i32>,
|
||||||
|
);
|
||||||
|
tests::seq_can_be_expressed_via_bind::<T, _, _, _, _, _>(
|
||||||
|
|| make_none(Some(|x| x + 3)),
|
||||||
|
|| Some(2),
|
||||||
|
);
|
||||||
|
tests::seq_can_be_expressed_via_bind::<T, _, _, _, _, _>(
|
||||||
|
|| make_none(Some(|x| x + 3)),
|
||||||
|
|| None::<i32>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fmap_can_be_expressed_via_bind() {
|
||||||
|
tests::fmap_can_be_expressed_via_bind::<T, _, _, _, _>(|x| x + 3, || Some(2));
|
||||||
|
tests::fmap_can_be_expressed_via_bind::<T, _, _, _, _>(|x| x + 3, || None::<i32>);
|
||||||
|
}
|
||||||
|
}
|
16
src/lib.rs
16
src/lib.rs
@ -1,14 +1,2 @@
|
|||||||
pub fn add(left: usize, right: usize) -> usize {
|
pub mod core;
|
||||||
left + right
|
pub mod func;
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_works() {
|
|
||||||
let result = add(2, 2);
|
|
||||||
assert_eq!(result, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user