Skip to main content

Thunk

Struct Thunk 

Source
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

AspectThunk<'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 caseGlue code, compositionDeep 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:

§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.
Source

pub fn new<F>(f: F) -> Self
where F: FnOnce() -> A + 'a,

Creates a new Thunk from a thunk.

§Type Signature

forall A. (() -> A) -> Thunk A

§Type Parameters
  • F: The type of the closure.
§Parameters
  • f: The thunk to wrap.
§Returns

A new Thunk instance.

§Examples
use fp_library::types::*;

let thunk = Thunk::new(|| 42);
assert_eq!(thunk.evaluate(), 42);
Source

pub fn pure(a: A) -> Self
where 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);
Source

pub fn defer<F>(f: F) -> Self
where F: FnOnce() -> Thunk<'a, A> + 'a,

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 a Thunk.
§Returns

A new Thunk instance.

§Examples
use fp_library::{brands::*, functions::*, types::*};

let thunk = Thunk::defer(|| pure::<ThunkBrand, _>(42));
assert_eq!(thunk.evaluate(), 42);
Source

pub fn bind<B: 'a, F>(self, f: F) -> Thunk<'a, B>
where F: FnOnce(A) -> Thunk<'a, B> + 'a,

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);
Source

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);
Source

pub fn evaluate(self) -> A

Forces evaluation and returns the result.

§Type Signature

forall A. Thunk A -> A

§Returns

The result of the computation.

§Examples
use fp_library::{brands::*, functions::*};

let thunk = pure::<ThunkBrand, _>(42);
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.
Source§

fn defer<F>(f: F) -> Self
where F: FnOnce() -> Self + 'a, Self: Sized,

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.
Source§

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.
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.
Source§

fn from(eval: Thunk<'a, A>) -> Self

§Type Signature

forall A. Thunk A -> Lazy A

§Parameters
  • eval: The thunk to convert.
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.
Source§

fn from(eval: Thunk<'a, A>) -> Self

§Type Signature

forall A E. Thunk A -> TryThunk A E

§Parameters
  • eval: The thunk to convert.
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.
Source§

fn empty() -> Self

Returns the identity Thunk.

§Type Signature

forall A. Monoid A => () -> Thunk A

§Returns

A Thunk producing the identity value of A.

§Examples
use fp_library::{classes::*, types::*};

let t: Thunk<String> = Thunk::empty();
assert_eq!(t.evaluate(), "");
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.
Source§

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 first Thunk.
  • b: The second Thunk.
§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> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.