//! 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 //! [`OptionClass::replace`] and [`OptionClass::discard_first`]/[`OptionClass::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 OptionClass; impl WeakFunctor for OptionClass { type F<'a, A: 'a> = Option; } impl Functor for OptionClass { 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 OptionClass { fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { Some(a) } } impl ApplicativeSeq for OptionClass { 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 OptionClass { 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 ApplicativeTuple for OptionClass { fn tuple<'a, A: 'a, B: 'a>((fa, fb): (Self::F<'a, A>, Self::F<'a, B>)) -> Self::F<'a, (A, B)> where Self: 'a, { Self::pure((fa?, fb?)) } } impl Applicative for OptionClass { fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> { fa?; fb } fn discard_second<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, A> { fb?; fa } } impl Monad for OptionClass { fn bind<'a, A: 'a, B: 'a>( fa: Self::F<'a, A>, f: impl 'a + FnOnce(A) -> Self::F<'a, B>, ) -> Self::F<'a, B> { f(fa?) } fn iterate_mut<'a, A: 'a, B: 'a>( mut a: A, mut f: impl 'a + FnMut(A) -> Self::F<'a, ControlFlow>, ) -> Self::F<'a, B> where Self: 'a, { loop { match f(a)? { ControlFlow::Continue(next_a) => a = next_a, ControlFlow::Break(b) => return Self::pure(b), }; } } fn iterate_argument<'a, A: 'a, B: 'a>( mut a: A, mut f: impl AIterative<'a, T = Self, A = A, B = B>, ) -> Self::F<'a, B> where Self: 'a, { loop { match f.next(a)? { ControlFlow::Continue((next_a, next_f)) => (a, f) = (next_a, next_f), ControlFlow::Break(b) => return Self::pure(b), } } } fn iterate<'a, B: 'a>(mut f: impl Iterative<'a, T = Self, B = B>) -> Self::F<'a, B> where Self: 'a, { loop { match f.next()? { ControlFlow::Continue(next_f) => f = next_f, ControlFlow::Break(b) => return Self::pure(b), } } } fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> { ffa? } } impl LocalFunctor for OptionClass { 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 MonadFail<()> for OptionClass { fn fail<'a, A: 'a>(_e: ()) -> Self::F<'a, A> where Self: 'a, { None } } #[cfg(test)] mod option_tests { use super::{test_suite, tests, Functor}; use super::OptionClass 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(); } }