//! Implementation of [`Monad`] for [`Option`]. //! //! If any of the input values are [`None`], you can expect the output to be [`None`] as well. //! That includes //! [`OptionInstance::replace`] and [`OptionInstance::discard_first`]/[`OptionInstance::discard_second`], //! even if the value of the option would be ignored. //! //! For [`Result`] alternative see [`super::result`] use crate::func::*; #[derive(SharedFunctor, CovariantFunctor)] pub struct OptionInstance; impl WeakFunctor for OptionInstance { type F<'a, A: 'a> = Option; } impl Functor for OptionInstance { fn fmap<'a, A: 'a, B: 'a>(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> { fa.map(f) } fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> where Self: 'a, { fa?; Self::pure(b) } fn void<'a, A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()> where Self: 'a, { fa?; Self::pure(()) } } impl Pure for OptionInstance { fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { Some(a) } } impl ApplicativeSeq for OptionInstance { fn seq<'a, A: 'a, B: 'a>( ff: Self::F<'a, impl 'a + FnOnce(A) -> B>, fa: Self::F<'a, A>, ) -> Self::F<'a, B> { Self::pure(ff?(fa?)) } } impl ApplicativeLA2 for OptionInstance { fn la2<'a, A: 'a, B: 'a, C: 'a>( f: impl 'a + FnOnce(A, B) -> C, fa: Self::F<'a, A>, fb: Self::F<'a, B>, ) -> Self::F<'a, C> { Self::pure(f(fa?, fb?)) } } impl<'a> ApplicativeTuple<'a> for OptionInstance { fn tuple((fa, fb): (Self::F<'a, A>, Self::F<'a, B>)) -> Self::F<'a, (A, B)> { Self::pure((fa?, fb?)) } } impl<'a> ApplicativeSelect<'a> for OptionInstance {} impl<'a> Applicative<'a> for OptionInstance { fn discard_first(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> { fa?; fb } fn discard_second(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, A> { fb?; fa } } impl<'a> Monad<'a> for OptionInstance { fn bind( fa: Self::F<'a, A>, f: impl 'a + FnOnce(A) -> Self::F<'a, B>, ) -> Self::F<'a, B> { f(fa?) } fn iterate(mut f: impl Iterative<'a, T = Self, B = B>) -> Self::F<'a, B> { loop { match f.next()? { ControlFlow::Continue(next_f) => f = next_f, ControlFlow::Break(b) => return Self::pure(b), } } } fn join(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> { ffa? } } impl LocalFunctor for OptionInstance { fn unstuff<'a, A: 'a, B: 'a>( state: Self::F<'a, ControlFlow>, ) -> ControlFlow, A> where Self: 'a, { match state { Some(ControlFlow::Continue(a)) => ControlFlow::Continue(a), Some(ControlFlow::Break(b)) => ControlFlow::Break(Some(b)), None => ControlFlow::Break(None), } } fn stuff<'a, A: 'a, T: 'a + Pure>(fa: Self::F<'a, T::F<'a, A>>) -> T::F<'a, Self::F<'a, A>> where Self: 'a, { match fa { Some(ua) => T::fmap(Some, ua), None => T::pure(None), } } } impl<'a> Fail<'a, ()> for OptionInstance { fn fail(_e: ()) -> Self::F<'a, A> { None } } #[cfg(test)] mod option_tests { use super::{test_suite, tests, Functor}; use super::OptionInstance as T; impl tests::Eqr for T { fn eqr<'a, A: PartialEq + std::fmt::Debug + 'a>( name: &'a str, left: Self::F<'a, A>, right: Self::F<'a, A>, ) -> tests::R { tests::eqr(name, left, right) } } impl test_suite::FunctorTestSuite for T { 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)); } } #[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 replace_none_b_is_none() { assert_eq!(T::replace(None::, 1), None); assert_eq!(T::void(None::), 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 monad_follows_laws() { test_suite::monad_follows_laws::().unwrap(); } }