//! 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 [`super::stackless`]. use std::{cell::RefCell, rc::Rc}; use crate::func::*; #[derive(CovariantFunctor)] pub struct LazyInstance; impl WeakFunctor for LazyInstance { type F<'a, A: 'a> = Box A>; } impl Functor for LazyInstance { fn fmap<'a, A: 'a, B: 'a>(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> { Box::new(|| f(fa())) } fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> { drop(fa); Box::new(|| b) } fn void<'a, A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()> { drop(fa); Box::new(|| ()) } } impl<'a> Pure<'a> for LazyInstance { fn pure(a: A) -> Self::F<'a, A> { Box::new(|| a) } } impl<'a> ApplicativeSeq<'a> for LazyInstance { fn seq( ff: Self::F<'a, impl 'a + FnOnce(A) -> B>, fa: Self::F<'a, A>, ) -> Self::F<'a, B> { Box::new(|| ff()(fa())) } } impl<'a> ApplicativeLA2<'a> for LazyInstance { fn la2( f: impl 'a + FnOnce(A, B) -> C, fa: Self::F<'a, A>, fb: Self::F<'a, B>, ) -> Self::F<'a, C> { Box::new(|| f(fa(), fb())) } } impl<'a> ApplicativeTuple<'a> for LazyInstance { fn tuple((fa, fb): (Self::F<'a, A>, Self::F<'a, B>)) -> Self::F<'a, (A, B)> { Box::new(|| (fa(), fb())) } } impl<'a> ApplicativeSelect<'a> for LazyInstance {} impl<'a> Applicative<'a> for LazyInstance { fn discard_first(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> { drop(fa); fb } fn discard_second(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, A> { drop(fb); fa } } impl<'a> Monad<'a> for LazyInstance { fn bind( fa: Self::F<'a, A>, f: impl 'a + FnOnce(A) -> Self::F<'a, B>, ) -> Self::F<'a, B> { Box::new(|| 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> { Box::new(|| ffa()()) } } fn unshare<'a, A: 'a + Clone>(shared: &mut Option A>>) -> A { let a = shared.take().expect( "cannot evaluate a missing shared lazy value. probably, the shared value depends on itself", )(); let cloned = a.clone(); *shared = Some(Box::new(|| cloned)); a } impl SharedFunctor for LazyInstance { type Shared<'a, A: 'a + Clone> = Rc A>>>> where Self: 'a; fn share<'a, A: 'a + Clone>(fa: Self::F<'a, A>) -> Self::Shared<'a, A> where Self: 'a, { Rc::new(RefCell::new(Some(fa))) } fn unshare<'a, A: 'a + Clone>(sa: Self::Shared<'a, A>) -> Self::F<'a, A> where Self: 'a, { Box::new(move || unshare(&mut *sa.borrow_mut())) } }