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.
§Examples
use fp_library::types::*;
let computation = Thunk::new(|| 5)
.map(|x| x * 2)
.map(|x| x + 1);
// No computation has happened yet!
// Only when we call evaluate() does it execute:
let result = computation.evaluate();
assert_eq!(result, 11);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::*, functions::*, classes::*};
let thunk = pure::<ThunkBrand, _>(42);
assert_eq!(thunk.evaluate(), 42);Sourcepub fn defer<F>(f: F) -> Self
pub fn defer<F>(f: F) -> Self
Defers a computation that returns a Thunk.
§Type Signature
forall A. (() -> Thunk A) -> Thunk A
§Type Parameters
F: The type of the closure.
§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, F>(self, f: F) -> Thunk<'a, B>
pub fn bind<B: 'a, F>(self, f: F) -> 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.F: The type of the function to apply.
§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, F>(self, f: F) -> Thunk<'a, B>where
F: FnOnce(A) -> B + 'a,
pub fn map<B: 'a, F>(self, f: F) -> Thunk<'a, B>where
F: FnOnce(A) -> B + 'a,
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.F: The type of the transformation function.
§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>(f: F) -> Self
fn defer<F>(f: F) -> Self
Creates a Thunk from a computation that produces it.
§Type Signature
forall A. (() -> Thunk A) -> Thunk A
§Type Parameters
F: The type of the closure.
§Parameters
f: A thunk that produces the thunk.
§Returns
The deferred thunk.
§Examples
use fp_library::{brands::*, functions::*, types::*, classes::Deferrable};
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§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§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> !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