//! Helper [Monad]s to defer execution until necessary. //! Wrapped value is just a box pointing to the constructor function. //! //! Due to semantical laziness, //! [`LazyInstance::replace`] and [`LazyInstance::discard_first`]/[`LazyInstance::discard_second`] //! actually fully cancel the "unnecessary" computation. //! //! For stackless execution see [`stackless`]. //! //! [`stackless`]: super::stackless use crate::func::class_prelude::*; pub struct LazyInstance; impl WeakFunctorAny for LazyInstance { type FAny<'a, A: 'a + Send> = Box A>; } impl<'a> Functor<'a> for LazyInstance { fn fmap( fa: Self::F, f: impl 'a + Send + FnOnce(A) -> B, ) -> Self::F { Box::new(|| f(fa())) } fn replace(fa: Self::F, b: B) -> Self::F { drop(fa); Box::new(|| b) } fn void(fa: Self::F) -> Self::F<()> { drop(fa); Box::new(|| ()) } } impl<'a> Pure<'a> for LazyInstance { fn pure(a: A) -> Self::F { Box::new(|| a) } } impl<'a> ApplicativeSeq<'a> for LazyInstance { fn seq( ff: Self::F B>, fa: Self::F, ) -> Self::F { Box::new(|| ff()(fa())) } } impl<'a> ApplicativeLA2<'a> for LazyInstance { fn la2( fa: Self::F, fb: Self::F, f: impl 'a + Send + FnOnce(A, B) -> C, ) -> Self::F { Box::new(|| f(fa(), fb())) } } impl<'a> ApplicativeTuple<'a> for LazyInstance { fn tuple((fa, fb): (Self::F, Self::F)) -> Self::F<(A, B)> { Box::new(|| (fa(), fb())) } } impl<'a> ApplicativeSelect<'a> for LazyInstance {} impl<'a> Applicative<'a> for LazyInstance { fn discard_first(fa: Self::F, fb: Self::F) -> Self::F { drop(fa); fb } fn discard_second(fa: Self::F, fb: Self::F) -> Self::F { drop(fb); fa } } impl<'a> Monad<'a> for LazyInstance { fn bind( fa: Self::F, f: impl 'a + Send + FnOnce(A) -> Self::F, ) -> Self::F { Box::new(|| f(fa())()) } fn iterate(mut f: impl Iterative<'a, T = Self, B = B>) -> Self::F { loop { match f.next()() { ControlFlow::Continue(next_f) => f = next_f, ControlFlow::Break(b) => return Self::pure(b), } } } fn join(ffa: Self::F>) -> Self::F { Box::new(|| ffa()()) } } #[cfg(test)] mod lazy_tests { use std::sync::Arc; use super::{test_suite, tests, LazyInstance}; type T = LazyInstance; impl<'a> tests::Eqr<'a> for T { fn eqr( name: &'a str, left: Self::F, right: Self::F, ) -> tests::R { tests::eqr(name, left(), right()) } } impl<'a> test_suite::FunctorTestSuite<'a> for T { fn sample>>)>( mut f: F, ) { f(Arc::new(|a| Box::new(|| a))); } } #[test] fn monad_follows_laws() { test_suite::monad_follows_laws::().unwrap(); } }