//! 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)] pub struct OptionInstance; impl WeakFunctor for OptionInstance { type F<'a, A: 'a> = Option; } impl<'a> Functor<'a> for OptionInstance { fn fmap(f: impl 'a + FnOnce(A) -> B, fa: Self::Fa) -> Self::Fa { fa.map(f) } fn replace(fa: Self::Fa, b: B) -> Self::Fa { fa?; Self::pure(b) } fn void(fa: Self::Fa) -> Self::Fa<()> { fa?; Self::pure(()) } } impl<'a> Pure<'a> for OptionInstance { fn pure(a: A) -> Self::Fa { Some(a) } } impl<'a> ApplicativeSeq<'a> for OptionInstance { fn seq(ff: Self::Fa B>, fa: Self::Fa) -> Self::Fa { Self::pure(ff?(fa?)) } } impl<'a> ApplicativeLA2<'a> for OptionInstance { fn la2( f: impl 'a + FnOnce(A, B) -> C, fa: Self::Fa, fb: Self::Fa, ) -> Self::Fa { Self::pure(f(fa?, fb?)) } } impl<'a> ApplicativeTuple<'a> for OptionInstance { fn tuple((fa, fb): (Self::Fa, Self::Fa)) -> Self::Fa<(A, B)> { Self::pure((fa?, fb?)) } } impl<'a> ApplicativeSelect<'a> for OptionInstance {} impl<'a> Applicative<'a> for OptionInstance { fn discard_first(fa: Self::Fa, fb: Self::Fa) -> Self::Fa { fa?; fb } fn discard_second(fa: Self::Fa, fb: Self::Fa) -> Self::Fa { fb?; fa } } impl<'a> Monad<'a> for OptionInstance { fn bind(fa: Self::Fa, f: impl 'a + FnOnce(A) -> Self::Fa) -> Self::Fa { f(fa?) } fn iterate(mut f: impl Iterative<'a, T = Self, B = B>) -> Self::Fa { loop { match f.next()? { ControlFlow::Continue(next_f) => f = next_f, ControlFlow::Break(b) => return Self::pure(b), } } } fn join(ffa: Self::Fa>) -> Self::Fa { ffa? } } impl<'a> LocalFunctor<'a> for OptionInstance { fn unstuff(state: Self::Fa>) -> ControlFlow, A> { match state { Some(ControlFlow::Continue(a)) => ControlFlow::Continue(a), Some(ControlFlow::Break(b)) => ControlFlow::Break(Some(b)), None => ControlFlow::Break(None), } } fn stuff>(fa: Self::Fa>) -> T::Fa> { match fa { Some(ua) => T::fmap(Some, ua), None => T::pure(None), } } } impl<'a> Fail<'a, ()> for OptionInstance { fn fail(_e: ()) -> Self::Fa { None } } #[cfg(test)] mod option_tests { use super::{test_suite, tests, Functor}; use super::OptionInstance as T; impl<'a> tests::Eqr<'a> for T { fn eqr( name: &'a str, left: Self::Fa, right: Self::Fa, ) -> tests::R { tests::eqr(name, left, right) } } impl<'a> test_suite::FunctorTestSuite<'a> for T { fn sample Self::Fa)>(mut f: F) { 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(); } }