pub struct Thunk<'a, A>(/* private fields */);Expand description
A deferred computation that produces a value of type A.
Thunk is NOT memoized - each call to Thunk::evaluate re-executes the computation.
This type exists to build computation chains without allocation overhead.
Unlike Trampoline, Thunk does NOT require 'static and CAN implement
HKT traits like Functor, Semimonad, etc.
§Higher-Kinded Type Representation
The higher-kinded representation of this type constructor is ThunkBrand,
which is fully polymorphic over the result type.
§Trade-offs vs Trampoline
| Aspect | Thunk<'a, A> | Trampoline<A> |
|---|---|---|
| HKT compatible | ✅ Yes | ❌ No (requires 'static) |
| Stack-safe | ⚠️ Partial (tail_rec_m only) | ✅ Yes (unlimited) |
| Lifetime | 'a (can borrow) | 'static only |
| Use case | Glue code, composition | Deep recursion, pipelines |
§Algebraic Properties
Thunk is a proper Monad:
pure(a).evaluate() == a(left identity).thunk.bind(pure) == thunk(right identity).thunk.bind(f).bind(g) == thunk.bind(|a| f(a).bind(g))(associativity).
§Limitations
Cannot implement Traversable: Thunk wraps Box<dyn FnOnce() -> A>, which cannot be cloned
because FnOnce is consumed when called. The Traversable trait
requires Clone bounds on the result type (to build the output structure), making it fundamentally
incompatible with Thunk’s design. This is an intentional trade-off: Thunk prioritizes
zero-overhead deferred execution and lifetime flexibility over structural cloning.
Implemented typeclasses:
- ✅
Functor,Foldable,Semimonad/Monad,Semiapplicative/Applicative - ❌
Traversable(requiresClone)
§Type Parameters
'a: The lifetime of the computation.A: The type of the value produced by the computation.
§Fields
0: The closure that performs the computation.
Implementations§
Source§impl<'a, A: 'a> Thunk<'a, A>
§Type Parameters
'a: The lifetime of the computation.
A: The type of the value produced by the computation.
impl<'a, A: 'a> Thunk<'a, A>
§Type Parameters
'a: The lifetime of the computation.A: The type of the value produced by the computation.
Sourcepub fn pure(a: A) -> Selfwhere
A: 'a,
pub fn pure(a: A) -> Selfwhere
A: 'a,
Returns a pure value (already computed).
§Type Signature
forall A. A -> Thunk A
§Parameters
a: The value to wrap.
§Returns
A new Thunk instance containing the value.
§Examples
use fp_library::{
brands::*,
classes::*,
functions::*,
};
let thunk = pure::<ThunkBrand, _>(42);
assert_eq!(thunk.evaluate(), 42);Sourcepub fn defer(f: impl FnOnce() -> Thunk<'a, A> + 'a) -> Self
pub fn defer(f: impl FnOnce() -> Thunk<'a, A> + 'a) -> Self
Defers a computation that returns a Thunk.
§Type Signature
forall A. (() -> Thunk A) -> Thunk A
§Parameters
f: The thunk that returns aThunk.
§Returns
A new Thunk instance.
§Examples
use fp_library::{
brands::*,
functions::*,
types::*,
};
let thunk = Thunk::defer(|| pure::<ThunkBrand, _>(42));
assert_eq!(thunk.evaluate(), 42);Sourcepub fn bind<B: 'a>(self, f: impl FnOnce(A) -> Thunk<'a, B> + 'a) -> Thunk<'a, B>
pub fn bind<B: 'a>(self, f: impl FnOnce(A) -> Thunk<'a, B> + 'a) -> Thunk<'a, B>
Monadic bind: chains computations.
Note: Each bind adds to the call stack. For deep recursion,
use Trampoline instead.
§Type Signature
forall A B. (Thunk A, A -> Thunk B) -> Thunk B
§Type Parameters
B: The type of the result of the new computation.
§Parameters
self: The thunk instance.f: The function to apply to the result of the computation.
§Returns
A new Thunk instance representing the chained computation.
§Examples
use fp_library::{
brands::*,
functions::*,
};
let thunk = pure::<ThunkBrand, _>(21).bind(|x| pure::<ThunkBrand, _>(x * 2));
assert_eq!(thunk.evaluate(), 42);Sourcepub fn map<B: 'a>(self, f: impl FnOnce(A) -> B + 'a) -> Thunk<'a, B>
pub fn map<B: 'a>(self, f: impl FnOnce(A) -> B + 'a) -> Thunk<'a, B>
Functor map: transforms the result.
§Type Signature
forall A B. (Thunk A, A -> B) -> Thunk B
§Type Parameters
B: The type of the result of the transformation.
§Parameters
self: The thunk instance.f: The function to apply to the result of the computation.
§Returns
A new Thunk instance with the transformed result.
§Examples
use fp_library::{
brands::*,
functions::*,
};
let thunk = pure::<ThunkBrand, _>(21).map(|x| x * 2);
assert_eq!(thunk.evaluate(), 42);Trait Implementations§
Source§impl<'a, A: 'a> Deferrable<'a> for Thunk<'a, A>
§Type Parameters
'a: The lifetime of the computation.
A: The type of the value produced by the computation.
impl<'a, A: 'a> Deferrable<'a> for Thunk<'a, A>
§Type Parameters
'a: The lifetime of the computation.A: The type of the value produced by the computation.
Source§fn defer(f: impl FnOnce() -> Self + 'a) -> Selfwhere
Self: Sized,
fn defer(f: impl FnOnce() -> Self + 'a) -> Selfwhere
Self: Sized,
Creates a Thunk from a computation that produces it.
§Type Signature
forall A. (() -> Thunk A) -> Thunk A
§Parameters
f: A thunk that produces the thunk.
§Returns
The deferred thunk.
§Examples
use fp_library::{
brands::*,
classes::Deferrable,
functions::*,
types::*,
};
let task: Thunk<i32> = Deferrable::defer(|| Thunk::pure(42));
assert_eq!(task.evaluate(), 42);Source§impl<'a, A, Config> From<Lazy<'a, A, Config>> for Thunk<'a, A>where
A: Clone + 'a,
Config: LazyConfig,
§Type Parameters
'a: The lifetime of the computation.
A: The type of the value produced by the computation.
Config: The memoization configuration.
impl<'a, A, Config> From<Lazy<'a, A, Config>> for Thunk<'a, A>where
A: Clone + 'a,
Config: LazyConfig,
§Type Parameters
'a: The lifetime of the computation.A: The type of the value produced by the computation.Config: The memoization configuration.
Source§fn from(lazy: Lazy<'a, A, Config>) -> Self
fn from(lazy: Lazy<'a, A, Config>) -> Self
§Type Signature
forall A Config. LazyConfig Config => Lazy A Config -> Thunk A Config
§Parameters
lazy: The lazy value to convert.
§Returns
A thunk that evaluates the lazy value.
§Examples
use fp_library::types::*;
let lazy = Lazy::<_, RcLazyConfig>::pure(42);
let thunk = Thunk::from(lazy);
assert_eq!(thunk.evaluate(), 42);Source§impl<'a, A> From<Thunk<'a, A>> for Lazy<'a, A, RcLazyConfig>
§Type Parameters
'a: The lifetime of the reference.
A: The type of the computed value.
impl<'a, A> From<Thunk<'a, A>> for Lazy<'a, A, RcLazyConfig>
§Type Parameters
'a: The lifetime of the reference.A: The type of the computed value.
Source§impl<'a, A: 'a, E: 'a> From<Thunk<'a, A>> for TryThunk<'a, A, E>
§Type Parameters
'a: The lifetime of the computation.
A: The type of the success value.
E: The type of the error value.
impl<'a, A: 'a, E: 'a> From<Thunk<'a, A>> for TryThunk<'a, A, E>
§Type Parameters
'a: The lifetime of the computation.A: The type of the success value.E: The type of the error value.
Source§fn from(eval: Thunk<'a, A>) -> Self
fn from(eval: Thunk<'a, A>) -> Self
§Type Signature
forall A E. Thunk A -> TryThunk A E
§Parameters
eval: The thunk to convert.
§Returns
A new TryThunk instance that wraps the thunk.
§Examples
use fp_library::types::*;
let thunk = Thunk::new(|| 42);
let try_thunk: TryThunk<i32, ()> = TryThunk::from(thunk);
assert_eq!(try_thunk.evaluate(), Ok(42));Source§impl<'a, A: Monoid + 'a> Monoid for Thunk<'a, A>
§Type Parameters
'a: The lifetime of the computation.
A: The type of the value produced by the computation.
impl<'a, A: Monoid + 'a> Monoid for Thunk<'a, A>
§Type Parameters
'a: The lifetime of the computation.A: The type of the value produced by the computation.
Source§impl<'a, A: Semigroup + 'a> Semigroup for Thunk<'a, A>
§Type Parameters
'a: The lifetime of the computation.
A: The type of the value produced by the computation.
impl<'a, A: Semigroup + 'a> Semigroup for Thunk<'a, A>
§Type Parameters
'a: The lifetime of the computation.A: The type of the value produced by the computation.
Source§fn append(a: Self, b: Self) -> Self
fn append(a: Self, b: Self) -> Self
Combines two Thunks by combining their results.
§Type Signature
forall A. Semigroup A => (Thunk A, Thunk A) -> Thunk A
§Parameters
a: The firstThunk.b: The secondThunk.
§Returns
A new Thunk containing the combined result.
§Examples
use fp_library::{
brands::*,
classes::*,
functions::*,
};
let t1 = pure::<ThunkBrand, _>("Hello".to_string());
let t2 = pure::<ThunkBrand, _>(" World".to_string());
let t3 = append::<_>(t1, t2);
assert_eq!(t3.evaluate(), "Hello World");Auto Trait Implementations§
impl<'a, A> Freeze for Thunk<'a, A>
impl<'a, A> !RefUnwindSafe for Thunk<'a, A>
impl<'a, A> !Send for Thunk<'a, A>
impl<'a, A> !Sync for Thunk<'a, A>
impl<'a, A> Unpin for Thunk<'a, A>
impl<'a, A> UnsafeUnpin for Thunk<'a, A>
impl<'a, A> !UnwindSafe for Thunk<'a, 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