pub struct Free<F, A>(/* private fields */)
where
F: Functor + 'static,
A: 'static;Expand description
The Free monad with O(1) bind via CatList.
This implementation follows “Reflection without Remorse” to ensure that left-associated binds do not degrade performance.
§HKT and Lifetime Limitations
Free does not implement HKT traits (like Functor, Monad) from this library.
§The Conflict
- The Traits: The
Kindtrait implemented by theFunctorhierarchy requires the type constructor to accept any lifetime'a(e.g.,type Of<'a, A> = Free<F, A>). - The Implementation: This implementation uses
Box<dyn Any>to type-erase continuations for the “Reflection without Remorse” optimization.dyn Anystrictly requiresA: 'static.
This creates an unresolvable conflict: Free cannot support non-static references (like &'a str),
so it cannot satisfy the Kind signature.
§Why not use the “Naive” Recursive Definition?
A naive definition (enum Free { Pure(A), Wrap(F<Box<Free<F, A>>>) }) would support lifetimes
and HKT traits. However, it was rejected because:
- Stack Safety:
runwould not be stack-safe for deep computations. - Performance:
bindwould be O(N), leading to quadratic complexity for sequences of binds.
This implementation prioritizes stack safety and O(1) bind over HKT trait compatibility.
§Type Parameters
F: The base functor (must implementFunctor).A: The result type.
§Examples
use fp_library::{brands::*, types::*};
let free = Free::<ThunkBrand, _>::pure(42);Implementations§
Source§impl<F, A> Free<F, A>where
F: Functor + 'static,
A: 'static,
impl<F, A> Free<F, A>where
F: Functor + 'static,
A: 'static,
Sourcepub fn wrap(fa: <F as Kind_cdc7cd43dac7585f>::Of<'static, Free<F, A>>) -> Self
pub fn wrap(fa: <F as Kind_cdc7cd43dac7585f>::Of<'static, Free<F, A>>) -> Self
Creates a suspended computation from a functor value.
§Type Signature
forall self. F (Free F A) -> self
§Parameters
fa: The functor value containing the next step.
§Returns
A Free computation that performs the effect fa.
§Examples
use fp_library::{brands::*, types::*};
let eval = Thunk::new(|| Free::pure(42));
let free = Free::<ThunkBrand, _>::wrap(eval);Sourcepub fn lift_f(fa: <F as Kind_cdc7cd43dac7585f>::Of<'static, A>) -> Self
pub fn lift_f(fa: <F as Kind_cdc7cd43dac7585f>::Of<'static, A>) -> Self
Lifts a functor value into the Free monad.
This is the primary way to inject effects into Free monad computations.
Equivalent to PureScript’s liftF and Haskell’s liftF.
§Type Signature
forall self. Functor self => F A -> self
§Implementation
liftF fa = wrap (map pure fa)§Parameters
fa: The functor value to lift.
§Returns
A Free computation that performs the effect and returns the result.
§Examples
use fp_library::{brands::*, types::*};
// Lift a simple computation
let thunk = Thunk::new(|| 42);
let free = Free::<ThunkBrand, _>::lift_f(thunk);
assert_eq!(free.evaluate(), 42);
// Build a computation from raw effects
let computation = Free::<ThunkBrand, _>::lift_f(Thunk::new(|| 10))
.bind(|x| Free::lift_f(Thunk::new(move || x * 2)))
.bind(|x| Free::lift_f(Thunk::new(move || x + 5)));
assert_eq!(computation.evaluate(), 25);Sourcepub fn bind<B: 'static>(
self,
f: impl FnOnce(A) -> Free<F, B> + 'static,
) -> Free<F, B>
pub fn bind<B: 'static>( self, f: impl FnOnce(A) -> Free<F, B> + 'static, ) -> Free<F, B>
Monadic bind with O(1) complexity.
§Type Signature
forall b. (A -> Free F b) -> Free F b
§Type Parameters
B: The result type of the new computation.
§Parameters
f: The function to apply to the result of this computation.
§Returns
A new Free computation that chains f after this computation.
§Examples
use fp_library::{brands::*, types::*};
let free = Free::<ThunkBrand, _>::pure(42)
.bind(|x| Free::pure(x + 1));Sourcepub fn evaluate(self) -> Awhere
F: Evaluable,
pub fn evaluate(self) -> Awhere
F: Evaluable,
Executes the Free computation, returning the final result.
This is the “trampoline” that iteratively processes the
CatList of continuations without growing the stack.
§Type Signature
Evaluable F => A
§Returns
The final result of the computation.
§Examples
use fp_library::{brands::*, types::*};
let free = Free::<ThunkBrand, _>::pure(42);
assert_eq!(free.evaluate(), 42);Trait Implementations§
Source§impl<A: 'static> Deferrable<'static> for Free<ThunkBrand, A>
impl<A: 'static> Deferrable<'static> for Free<ThunkBrand, A>
Source§fn defer<F>(f: F) -> Self
fn defer<F>(f: F) -> Self
Creates a Free computation from a thunk.
This delegates to Free::wrap and Thunk::new.
§Type Signature
forall self. Deferrable self => (() -> self) -> self
§Type Parameters
F: The type of the thunk.
§Parameters
f: A thunk that produces the free computation.
§Returns
The deferred free computation.
§Examples
use fp_library::{brands::*, functions::*, types::*, classes::Deferrable};
let task: Free<ThunkBrand, i32> = Deferrable::defer(|| Free::pure(42));
assert_eq!(task.evaluate(), 42);Auto Trait Implementations§
impl<F, A> Freeze for Free<F, A>
impl<F, A> !RefUnwindSafe for Free<F, A>
impl<F, A> !Send for Free<F, A>
impl<F, A> !Sync for Free<F, A>
impl<F, A> Unpin for Free<F, A>
impl<F, A> !UnwindSafe for Free<F, A>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more