Skip to main content

fp_library/types/
lazy.rs

1//! Memoized lazy evaluation with shared cache semantics.
2//!
3//! Computes a value at most once on first access and caches the result. All clones share the same cache. Available in both single-threaded [`RcLazy`] and thread-safe [`ArcLazy`] variants.
4//!
5//! ## Why `Lazy` does not implement `Functor`
6//!
7//! [`Lazy::evaluate`] returns `&A` (a reference to the cached value), not an owned `A`.
8//! The standard [`Functor`](crate::classes::Functor) trait requires `A -> B`, which would
9//! need either cloning or consuming the cached value. Instead, `Lazy` implements
10//! [`RefFunctor`](crate::classes::RefFunctor) (and [`SendRefFunctor`](crate::classes::SendRefFunctor)
11//! for `ArcLazy`), whose `ref_map` takes `&A -> B`. Use [`ref_map`](crate::functions::ref_map) or
12//! [`send_ref_map`](crate::functions::send_ref_map) to map over lazy values.
13
14#[fp_macros::document_module]
15mod inner {
16	use {
17		crate::{
18			Apply,
19			brands::{
20				ArcBrand,
21				LazyBrand,
22				RcBrand,
23			},
24			classes::{
25				CloneableFn,
26				Deferrable,
27				Foldable,
28				FoldableWithIndex,
29				Monoid,
30				RefFunctor,
31				Semigroup,
32				SendDeferrable,
33				SendRefFunctor,
34				WithIndex,
35			},
36			impl_kind,
37			kinds::*,
38			types::{
39				SendThunk,
40				Thunk,
41				Trampoline,
42			},
43		},
44		fp_macros::*,
45		std::{
46			cell::LazyCell,
47			fmt,
48			hash::{
49				Hash,
50				Hasher,
51			},
52			rc::Rc,
53			sync::{
54				Arc,
55				LazyLock,
56			},
57		},
58	};
59
60	pub use crate::classes::{
61		LazyConfig,
62		TryLazyConfig,
63	};
64
65	/// Single-threaded memoization using [`Rc<LazyCell>`].
66	///
67	/// Not thread-safe. Use [`ArcLazyConfig`] for multi-threaded contexts.
68	pub struct RcLazyConfig;
69
70	impl LazyConfig for RcLazyConfig {
71		type Lazy<'a, A: 'a> = Rc<LazyCell<A, Box<dyn FnOnce() -> A + 'a>>>;
72		type PointerBrand = RcBrand;
73		type Thunk<'a, A: 'a> = dyn FnOnce() -> A + 'a;
74
75		/// Creates a new lazy cell from an initializer.
76		#[document_signature]
77		///
78		#[document_type_parameters("The lifetime of the computation.", "The type of the value.")]
79		///
80		#[document_parameters("The initializer thunk.")]
81		///
82		#[document_returns("A new lazy cell.")]
83		///
84		#[document_examples]
85		///
86		/// ```
87		/// use fp_library::{
88		/// 	classes::*,
89		/// 	types::*,
90		/// };
91		///
92		/// let lazy = RcLazyConfig::lazy_new(Box::new(|| 42));
93		/// assert_eq!(*RcLazyConfig::evaluate(&lazy), 42);
94		/// ```
95		fn lazy_new<'a, A: 'a>(f: Box<Self::Thunk<'a, A>>) -> Self::Lazy<'a, A> {
96			Rc::new(LazyCell::new(f))
97		}
98
99		/// Forces evaluation and returns a reference.
100		#[document_signature]
101		///
102		#[document_type_parameters(
103			"The lifetime of the computation.",
104			"The borrow lifetime.",
105			"The type of the value."
106		)]
107		///
108		#[document_parameters("The lazy cell to evaluate.")]
109		///
110		#[document_returns("A reference to the value.")]
111		///
112		#[document_examples]
113		///
114		/// ```
115		/// use fp_library::{
116		/// 	classes::*,
117		/// 	types::*,
118		/// };
119		///
120		/// let lazy = RcLazyConfig::lazy_new(Box::new(|| 42));
121		/// assert_eq!(*RcLazyConfig::evaluate(&lazy), 42);
122		/// ```
123		fn evaluate<'a, 'b, A: 'a>(lazy: &'b Self::Lazy<'a, A>) -> &'b A {
124			LazyCell::force(lazy)
125		}
126	}
127
128	impl TryLazyConfig for RcLazyConfig {
129		type TryLazy<'a, A: 'a, E: 'a> =
130			Rc<LazyCell<Result<A, E>, Box<dyn FnOnce() -> Result<A, E> + 'a>>>;
131		type TryThunk<'a, A: 'a, E: 'a> = dyn FnOnce() -> Result<A, E> + 'a;
132
133		/// Creates a new fallible lazy cell from an initializer.
134		#[document_signature]
135		///
136		#[document_type_parameters(
137			"The lifetime of the computation.",
138			"The type of the value.",
139			"The type of the error."
140		)]
141		///
142		#[document_parameters("The initializer thunk.")]
143		///
144		#[document_returns("A new fallible lazy cell.")]
145		///
146		#[document_examples]
147		///
148		/// ```
149		/// use fp_library::{
150		/// 	classes::*,
151		/// 	types::*,
152		/// };
153		///
154		/// let lazy = RcLazyConfig::try_lazy_new(Box::new(|| Ok::<i32, ()>(42)));
155		/// assert_eq!(RcLazyConfig::try_evaluate(&lazy), Ok(&42));
156		/// ```
157		fn try_lazy_new<'a, A: 'a, E: 'a>(
158			f: Box<Self::TryThunk<'a, A, E>>
159		) -> Self::TryLazy<'a, A, E> {
160			Rc::new(LazyCell::new(f))
161		}
162
163		/// Forces evaluation and returns a reference to the result.
164		#[document_signature]
165		///
166		#[document_type_parameters(
167			"The lifetime of the computation.",
168			"The borrow lifetime.",
169			"The type of the value.",
170			"The type of the error."
171		)]
172		///
173		#[document_parameters("The fallible lazy cell to evaluate.")]
174		///
175		#[document_returns("A result containing a reference to the value or error.")]
176		///
177		#[document_examples]
178		///
179		/// ```
180		/// use fp_library::{
181		/// 	classes::*,
182		/// 	types::*,
183		/// };
184		///
185		/// let lazy = RcLazyConfig::try_lazy_new(Box::new(|| Ok::<i32, ()>(42)));
186		/// assert_eq!(RcLazyConfig::try_evaluate(&lazy), Ok(&42));
187		/// ```
188		fn try_evaluate<'a, 'b, A: 'a, E: 'a>(
189			lazy: &'b Self::TryLazy<'a, A, E>
190		) -> Result<&'b A, &'b E> {
191			LazyCell::force(lazy).as_ref()
192		}
193	}
194
195	/// Thread-safe memoization using [`Arc<LazyLock>`].
196	///
197	/// Requires `A: Send + Sync` for the value type.
198	pub struct ArcLazyConfig;
199
200	impl LazyConfig for ArcLazyConfig {
201		type Lazy<'a, A: 'a> = Arc<LazyLock<A, Box<dyn FnOnce() -> A + Send + 'a>>>;
202		type PointerBrand = ArcBrand;
203		type Thunk<'a, A: 'a> = dyn FnOnce() -> A + Send + 'a;
204
205		/// Creates a new lazy cell from an initializer.
206		#[document_signature]
207		///
208		#[document_type_parameters("The lifetime of the computation.", "The type of the value.")]
209		///
210		#[document_parameters("The initializer thunk.")]
211		///
212		#[document_returns("A new lazy cell.")]
213		///
214		#[document_examples]
215		///
216		/// ```
217		/// use fp_library::{
218		/// 	classes::*,
219		/// 	types::*,
220		/// };
221		///
222		/// let lazy = ArcLazyConfig::lazy_new(Box::new(|| 42));
223		/// assert_eq!(*ArcLazyConfig::evaluate(&lazy), 42);
224		/// ```
225		fn lazy_new<'a, A: 'a>(f: Box<Self::Thunk<'a, A>>) -> Self::Lazy<'a, A> {
226			Arc::new(LazyLock::new(f))
227		}
228
229		/// Forces evaluation and returns a reference.
230		#[document_signature]
231		///
232		#[document_type_parameters(
233			"The lifetime of the computation.",
234			"The borrow lifetime.",
235			"The type of the value."
236		)]
237		///
238		#[document_parameters("The lazy cell to evaluate.")]
239		///
240		#[document_returns("A reference to the value.")]
241		///
242		#[document_examples]
243		///
244		/// ```
245		/// use fp_library::{
246		/// 	classes::*,
247		/// 	types::*,
248		/// };
249		///
250		/// let lazy = ArcLazyConfig::lazy_new(Box::new(|| 42));
251		/// assert_eq!(*ArcLazyConfig::evaluate(&lazy), 42);
252		/// ```
253		fn evaluate<'a, 'b, A: 'a>(lazy: &'b Self::Lazy<'a, A>) -> &'b A {
254			LazyLock::force(lazy)
255		}
256	}
257
258	impl TryLazyConfig for ArcLazyConfig {
259		type TryLazy<'a, A: 'a, E: 'a> =
260			Arc<LazyLock<Result<A, E>, Box<dyn FnOnce() -> Result<A, E> + Send + 'a>>>;
261		type TryThunk<'a, A: 'a, E: 'a> = dyn FnOnce() -> Result<A, E> + Send + 'a;
262
263		/// Creates a new fallible lazy cell from an initializer.
264		#[document_signature]
265		///
266		#[document_type_parameters(
267			"The lifetime of the computation.",
268			"The type of the value.",
269			"The type of the error."
270		)]
271		///
272		#[document_parameters("The initializer thunk.")]
273		///
274		#[document_returns("A new fallible lazy cell.")]
275		///
276		#[document_examples]
277		///
278		/// ```
279		/// use fp_library::{
280		/// 	classes::*,
281		/// 	types::*,
282		/// };
283		///
284		/// let lazy = ArcLazyConfig::try_lazy_new(Box::new(|| Ok::<i32, ()>(42)));
285		/// assert_eq!(ArcLazyConfig::try_evaluate(&lazy), Ok(&42));
286		/// ```
287		fn try_lazy_new<'a, A: 'a, E: 'a>(
288			f: Box<Self::TryThunk<'a, A, E>>
289		) -> Self::TryLazy<'a, A, E> {
290			Arc::new(LazyLock::new(f))
291		}
292
293		/// Forces evaluation and returns a reference to the result.
294		#[document_signature]
295		///
296		#[document_type_parameters(
297			"The lifetime of the computation.",
298			"The borrow lifetime.",
299			"The type of the value.",
300			"The type of the error."
301		)]
302		///
303		#[document_parameters("The fallible lazy cell to evaluate.")]
304		///
305		#[document_returns("A result containing a reference to the value or error.")]
306		///
307		#[document_examples]
308		///
309		/// ```
310		/// use fp_library::{
311		/// 	classes::*,
312		/// 	types::*,
313		/// };
314		///
315		/// let lazy = ArcLazyConfig::try_lazy_new(Box::new(|| Ok::<i32, ()>(42)));
316		/// assert_eq!(ArcLazyConfig::try_evaluate(&lazy), Ok(&42));
317		/// ```
318		fn try_evaluate<'a, 'b, A: 'a, E: 'a>(
319			lazy: &'b Self::TryLazy<'a, A, E>
320		) -> Result<&'b A, &'b E> {
321			LazyLock::force(lazy).as_ref()
322		}
323	}
324
325	/// A lazily-computed, memoized value with shared semantics.
326	///
327	/// The computation runs at most once; subsequent accesses return the cached value.
328	/// Cloning a `Lazy` shares the underlying cache, so all clones see the same value.
329	///
330	/// ### Panics
331	///
332	/// If the initializer closure panics, the underlying [`LazyCell`](std::cell::LazyCell)
333	/// (for [`RcLazyConfig`]) or [`LazyLock`](std::sync::LazyLock) (for [`ArcLazyConfig`])
334	/// is poisoned. Any subsequent call to [`evaluate`](Lazy::evaluate) on the same instance
335	/// or any of its clones will panic again. For panic-safe memoization, use
336	/// [`TryLazy`](crate::types::TryLazy) with a closure that catches panics via
337	/// [`std::panic::catch_unwind`].
338	///
339	/// ### Higher-Kinded Type Representation
340	///
341	/// The higher-kinded representation of this type constructor is [`LazyBrand<Config>`](crate::brands::LazyBrand),
342	/// which is parameterized by the memoization configuration and is polymorphic over the computed value type.
343	#[document_type_parameters(
344		"The lifetime of the computation.",
345		"The type of the computed value.",
346		"The memoization configuration (determines Rc vs Arc)."
347	)]
348	///
349	pub struct Lazy<'a, A, Config: LazyConfig = RcLazyConfig>(
350		/// The internal lazy cell.
351		pub(crate) Config::Lazy<'a, A>,
352	)
353	where
354		A: 'a;
355
356	#[document_type_parameters(
357		"The lifetime of the computation.",
358		"The type of the computed value.",
359		"The memoization configuration (determines Rc vs Arc)."
360	)]
361	#[document_parameters("The instance to clone.")]
362	impl<'a, A, Config: LazyConfig> Clone for Lazy<'a, A, Config>
363	where
364		A: 'a,
365	{
366		#[document_signature]
367		#[document_returns("A new `Lazy` instance that shares the same underlying memoized value.")]
368		#[document_examples]
369		///
370		/// ```
371		/// use fp_library::{
372		/// 	classes::*,
373		/// 	types::*,
374		/// };
375		///
376		/// let memo = Lazy::<_, RcLazyConfig>::new(|| 5);
377		/// let shared = memo.clone();
378		///
379		/// // First force computes and caches:
380		/// let value = memo.evaluate();
381		///
382		/// // Second force returns cached value (shared sees same result):
383		/// assert_eq!(shared.evaluate(), value);
384		/// ```
385		fn clone(&self) -> Self {
386			Self(self.0.clone())
387		}
388	}
389
390	#[document_type_parameters(
391		"The lifetime of the computation.",
392		"The type of the computed value.",
393		"The memoization configuration (determines Rc vs Arc)."
394	)]
395	#[document_parameters("The lazy instance.")]
396	impl<'a, A, Config: LazyConfig> Lazy<'a, A, Config>
397	where
398		A: 'a,
399	{
400		/// Gets the memoized value, computing on first access.
401		#[document_signature]
402		///
403		#[document_returns("A reference to the memoized value.")]
404		///
405		#[document_examples]
406		///
407		/// ```
408		/// use fp_library::{
409		/// 	classes::*,
410		/// 	types::*,
411		/// };
412		///
413		/// let memo = Lazy::<_, RcLazyConfig>::new(|| 42);
414		/// assert_eq!(*memo.evaluate(), 42);
415		/// ```
416		#[inline]
417		pub fn evaluate(&self) -> &A {
418			Config::evaluate(&self.0)
419		}
420	}
421
422	#[document_type_parameters(
423		"The lifetime of the computation.",
424		"The type of the computed value."
425	)]
426	#[document_parameters("The lazy instance.")]
427	impl<'a, A> Lazy<'a, A, RcLazyConfig>
428	where
429		A: 'a,
430	{
431		/// Creates a new Lazy that will run `f` on first access.
432		#[document_signature]
433		///
434		#[document_parameters("The closure that produces the value.")]
435		///
436		#[document_returns("A new `Lazy` instance.")]
437		///
438		#[inline]
439		#[document_examples]
440		///
441		/// ```
442		/// use fp_library::{
443		/// 	classes::*,
444		/// 	types::*,
445		/// };
446		///
447		/// let memo = Lazy::<_, RcLazyConfig>::new(|| 42);
448		/// assert_eq!(*memo.evaluate(), 42);
449		/// ```
450		pub fn new(f: impl FnOnce() -> A + 'a) -> Self {
451			Lazy(RcLazyConfig::lazy_new(Box::new(f)))
452		}
453
454		/// Creates a `Lazy` from an already-computed value.
455		///
456		/// The value is immediately available without any computation.
457		#[document_signature]
458		///
459		#[document_parameters("The pre-computed value to wrap.")]
460		///
461		#[document_returns("A new `Lazy` instance containing the value.")]
462		///
463		#[inline]
464		#[document_examples]
465		///
466		/// ```
467		/// use fp_library::{
468		/// 	classes::*,
469		/// 	types::*,
470		/// };
471		///
472		/// let lazy = Lazy::<_, RcLazyConfig>::pure(42);
473		/// assert_eq!(*lazy.evaluate(), 42);
474		/// ```
475		pub fn pure(a: A) -> Self {
476			Lazy(RcLazyConfig::lazy_new(Box::new(move || a)))
477		}
478
479		/// Returns a clone of the memoized value, computing on first access.
480		///
481		/// This is a convenience wrapper around [`evaluate`](Lazy::evaluate) for cases
482		/// where an owned value is needed rather than a reference.
483		#[document_signature]
484		///
485		#[document_returns("An owned clone of the memoized value.")]
486		///
487		#[document_examples]
488		///
489		/// ```
490		/// use fp_library::{
491		/// 	classes::*,
492		/// 	types::*,
493		/// };
494		///
495		/// let memo = RcLazy::new(|| vec![1, 2, 3]);
496		/// let owned: Vec<i32> = memo.evaluate_owned();
497		/// assert_eq!(owned, vec![1, 2, 3]);
498		/// ```
499		#[inline]
500		pub fn evaluate_owned(&self) -> A
501		where
502			A: Clone, {
503			self.evaluate().clone()
504		}
505
506		/// Maps a function over the memoized value by reference.
507		///
508		/// This is the inherent method form of [`RefFunctor::ref_map`](crate::classes::ref_functor::RefFunctor::ref_map).
509		/// The mapping function receives a reference to the cached value and returns a new value,
510		/// which is itself lazily memoized.
511		#[document_signature]
512		#[document_type_parameters("The type of the result.")]
513		#[document_parameters("The function to apply to the memoized value.")]
514		#[document_returns("A new `Lazy` instance containing the mapped value.")]
515		#[document_examples]
516		///
517		/// ```
518		/// use fp_library::{
519		/// 	classes::*,
520		/// 	types::*,
521		/// };
522		///
523		/// let memo = Lazy::<_, RcLazyConfig>::new(|| 10);
524		/// let mapped = memo.ref_map(|x| *x * 2);
525		/// assert_eq!(*mapped.evaluate(), 20);
526		/// ```
527		#[inline]
528		pub fn ref_map<B: 'a>(
529			self,
530			f: impl FnOnce(&A) -> B + 'a,
531		) -> Lazy<'a, B, RcLazyConfig> {
532			RcLazy::new(move || f(self.evaluate()))
533		}
534	}
535
536	#[document_type_parameters(
537		"The lifetime of the computation.",
538		"The type of the computed value."
539	)]
540	impl<'a, A> From<Thunk<'a, A>> for Lazy<'a, A, RcLazyConfig> {
541		#[document_signature]
542		#[document_parameters("The thunk to convert.")]
543		#[document_returns("A new `Lazy` instance that will evaluate the thunk on first access.")]
544		#[document_examples]
545		///
546		/// ```
547		/// use fp_library::{
548		/// 	classes::*,
549		/// 	types::*,
550		/// };
551		/// let thunk = Thunk::new(|| 42);
552		/// let lazy: RcLazy<i32> = Lazy::from(thunk);
553		/// assert_eq!(*lazy.evaluate(), 42);
554		/// ```
555		fn from(eval: Thunk<'a, A>) -> Self {
556			Self::new(move || eval.evaluate())
557		}
558	}
559
560	#[document_type_parameters(
561		"The lifetime of the computation.",
562		"The type of the computed value."
563	)]
564	impl<'a, A: 'static> From<Trampoline<A>> for Lazy<'a, A, RcLazyConfig> {
565		#[document_signature]
566		#[document_parameters("The trampoline to convert.")]
567		#[document_returns(
568			"A new `Lazy` instance that will evaluate the trampoline on first access."
569		)]
570		#[document_examples]
571		///
572		/// ```
573		/// use fp_library::{
574		/// 	classes::*,
575		/// 	types::*,
576		/// };
577		/// let task = Trampoline::pure(42);
578		/// let lazy: RcLazy<i32> = Lazy::from(task);
579		/// assert_eq!(*lazy.evaluate(), 42);
580		/// ```
581		fn from(task: Trampoline<A>) -> Self {
582			Self::new(move || task.evaluate())
583		}
584	}
585
586	#[document_type_parameters(
587		"The lifetime of the computation.",
588		"The type of the computed value."
589	)]
590	impl<'a, A: Send + Sync + 'a> From<Thunk<'a, A>> for Lazy<'a, A, ArcLazyConfig> {
591		/// Converts a [`Thunk`] into an [`ArcLazy`] by eagerly evaluating the thunk.
592		///
593		/// Thunk is `!Send`, so the value must be computed immediately to cross
594		/// into the thread-safe `ArcLazy` world.
595		#[document_signature]
596		#[document_parameters("The thunk to convert.")]
597		#[document_returns("A new `Lazy` instance containing the eagerly evaluated value.")]
598		#[document_examples]
599		///
600		/// ```
601		/// use fp_library::{
602		/// 	classes::*,
603		/// 	types::*,
604		/// };
605		/// let thunk = Thunk::new(|| 42);
606		/// let lazy: ArcLazy<i32> = ArcLazy::from(thunk);
607		/// assert_eq!(*lazy.evaluate(), 42);
608		/// ```
609		fn from(eval: Thunk<'a, A>) -> Self {
610			Self::pure(eval.evaluate())
611		}
612	}
613
614	#[document_type_parameters(
615		"The lifetime of the computation.",
616		"The type of the computed value."
617	)]
618	impl<'a, A: Send + Sync + 'static> From<Trampoline<A>> for Lazy<'a, A, ArcLazyConfig> {
619		/// Converts a [`Trampoline`] into an [`ArcLazy`] by eagerly evaluating the trampoline.
620		///
621		/// Trampoline is `!Send`, so the value must be computed immediately to cross
622		/// into the thread-safe `ArcLazy` world.
623		#[document_signature]
624		#[document_parameters("The trampoline to convert.")]
625		#[document_returns("A new `Lazy` instance containing the eagerly evaluated value.")]
626		#[document_examples]
627		///
628		/// ```
629		/// use fp_library::{
630		/// 	classes::*,
631		/// 	types::*,
632		/// };
633		/// let task = Trampoline::pure(42);
634		/// let lazy: ArcLazy<i32> = ArcLazy::from(task);
635		/// assert_eq!(*lazy.evaluate(), 42);
636		/// ```
637		fn from(task: Trampoline<A>) -> Self {
638			Self::pure(task.evaluate())
639		}
640	}
641
642	#[document_type_parameters(
643		"The lifetime of the computation.",
644		"The type of the computed value."
645	)]
646	impl<'a, A: 'a> From<SendThunk<'a, A>> for Lazy<'a, A, ArcLazyConfig> {
647		/// Converts a [`SendThunk`] into an [`ArcLazy`] without eager evaluation.
648		///
649		/// Because `SendThunk` already satisfies `Send`, the inner closure can be
650		/// passed directly into `ArcLazy`, deferring computation until first access.
651		#[document_signature]
652		#[document_parameters("The send thunk to convert.")]
653		#[document_returns("A new `ArcLazy` wrapping the deferred computation.")]
654		#[document_examples]
655		///
656		/// ```
657		/// use fp_library::{
658		/// 	classes::*,
659		/// 	types::*,
660		/// };
661		/// let thunk = SendThunk::new(|| 42);
662		/// let lazy: ArcLazy<i32> = ArcLazy::from(thunk);
663		/// assert_eq!(*lazy.evaluate(), 42);
664		/// ```
665		fn from(thunk: SendThunk<'a, A>) -> Self {
666			Self::new(move || thunk.evaluate())
667		}
668	}
669
670	#[document_type_parameters(
671		"The lifetime of the computation.",
672		"The type of the computed value."
673	)]
674	impl<'a, A: Clone + Send + Sync + 'a> From<Lazy<'a, A, RcLazyConfig>>
675		for Lazy<'a, A, ArcLazyConfig>
676	{
677		/// Converts an [`RcLazy`] into an [`ArcLazy`] by eagerly evaluating and cloning the value.
678		///
679		/// `RcLazy` is `!Send`, so the value must be computed immediately and cloned
680		/// into the thread-safe `ArcLazy` world.
681		#[document_signature]
682		#[document_parameters("The `RcLazy` instance to convert.")]
683		#[document_returns(
684			"A new `ArcLazy` instance containing a clone of the eagerly evaluated value."
685		)]
686		#[document_examples]
687		///
688		/// ```
689		/// use fp_library::{
690		/// 	classes::*,
691		/// 	types::*,
692		/// };
693		///
694		/// let rc_lazy = RcLazy::new(|| 42);
695		/// let arc_lazy: ArcLazy<i32> = ArcLazy::from(rc_lazy);
696		/// assert_eq!(*arc_lazy.evaluate(), 42);
697		/// ```
698		fn from(source: Lazy<'a, A, RcLazyConfig>) -> Self {
699			Self::pure(source.evaluate().clone())
700		}
701	}
702
703	#[document_type_parameters(
704		"The lifetime of the computation.",
705		"The type of the computed value."
706	)]
707	impl<'a, A: Clone + 'a> From<Lazy<'a, A, ArcLazyConfig>> for Lazy<'a, A, RcLazyConfig> {
708		/// Converts an [`ArcLazy`] into an [`RcLazy`] by eagerly evaluating and cloning the value.
709		///
710		/// The value is computed immediately and cloned into a new single-threaded
711		/// `RcLazy` instance.
712		#[document_signature]
713		#[document_parameters("The `ArcLazy` instance to convert.")]
714		#[document_returns(
715			"A new `RcLazy` instance containing a clone of the eagerly evaluated value."
716		)]
717		#[document_examples]
718		///
719		/// ```
720		/// use fp_library::{
721		/// 	classes::*,
722		/// 	types::*,
723		/// };
724		///
725		/// let arc_lazy = ArcLazy::new(|| 42);
726		/// let rc_lazy: RcLazy<i32> = RcLazy::from(arc_lazy);
727		/// assert_eq!(*rc_lazy.evaluate(), 42);
728		/// ```
729		fn from(source: Lazy<'a, A, ArcLazyConfig>) -> Self {
730			Self::pure(source.evaluate().clone())
731		}
732	}
733
734	#[document_type_parameters(
735		"The lifetime of the computation.",
736		"The type of the computed value."
737	)]
738	#[document_parameters("The lazy instance.")]
739	impl<'a, A> Lazy<'a, A, ArcLazyConfig>
740	where
741		A: 'a,
742	{
743		/// Creates a new Lazy that will run `f` on first access.
744		#[document_signature]
745		///
746		#[document_parameters("The closure that produces the value.")]
747		///
748		#[document_returns("A new `Lazy` instance.")]
749		///
750		#[inline]
751		#[document_examples]
752		///
753		/// ```
754		/// use fp_library::{
755		/// 	classes::*,
756		/// 	types::*,
757		/// };
758		///
759		/// let lazy = Lazy::<_, ArcLazyConfig>::new(|| 42);
760		/// assert_eq!(*lazy.evaluate(), 42);
761		/// ```
762		pub fn new(f: impl FnOnce() -> A + Send + 'a) -> Self {
763			Lazy(ArcLazyConfig::lazy_new(Box::new(f)))
764		}
765
766		/// Creates a `Lazy` from an already-computed value.
767		///
768		/// The value is immediately available without any computation.
769		/// Requires `Send` since `ArcLazy` is thread-safe.
770		#[document_signature]
771		///
772		#[document_parameters("The pre-computed value to wrap.")]
773		///
774		#[document_returns("A new `Lazy` instance containing the value.")]
775		///
776		#[inline]
777		#[document_examples]
778		///
779		/// ```
780		/// use fp_library::{
781		/// 	classes::*,
782		/// 	types::*,
783		/// };
784		///
785		/// let lazy = Lazy::<_, ArcLazyConfig>::pure(42);
786		/// assert_eq!(*lazy.evaluate(), 42);
787		/// ```
788		pub fn pure(a: A) -> Self
789		where
790			A: Send + Sync, {
791			Lazy(ArcLazyConfig::lazy_new(Box::new(move || a)))
792		}
793
794		/// Returns a clone of the memoized value, computing on first access.
795		///
796		/// This is a convenience wrapper around [`evaluate`](Lazy::evaluate) for cases
797		/// where an owned value is needed rather than a reference. Requires `Send + Sync`
798		/// since `ArcLazy` is thread-safe.
799		#[document_signature]
800		///
801		#[document_returns("An owned clone of the memoized value.")]
802		///
803		#[document_examples]
804		///
805		/// ```
806		/// use fp_library::{
807		/// 	classes::*,
808		/// 	types::*,
809		/// };
810		///
811		/// let memo = ArcLazy::new(|| vec![1, 2, 3]);
812		/// let owned: Vec<i32> = memo.evaluate_owned();
813		/// assert_eq!(owned, vec![1, 2, 3]);
814		/// ```
815		#[inline]
816		pub fn evaluate_owned(&self) -> A
817		where
818			A: Clone + Send + Sync, {
819			self.evaluate().clone()
820		}
821	}
822
823	#[document_type_parameters(
824		"The lifetime of the computation.",
825		"The type of the computed value."
826	)]
827	#[document_parameters("The lazy value to map over.")]
828	impl<'a, A: 'a> Lazy<'a, A, ArcLazyConfig> {
829		/// Maps a function over the memoized value by reference.
830		///
831		/// This is the `ArcLazy` counterpart of [`RcLazy::ref_map`](Lazy::ref_map).
832		/// The mapping function receives a reference to the cached value and returns a new value,
833		/// which is itself lazily memoized.
834		///
835		/// Note: A blanket `RefFunctor` trait impl is not provided for `LazyBrand<ArcLazyConfig>`
836		/// because the `RefFunctor` trait does not require `Send` on the mapping function, but
837		/// `ArcLazy::new` requires `Send`. This inherent method adds the necessary `Send` bounds
838		/// explicitly.
839		#[document_signature]
840		#[document_type_parameters("The type of the result.")]
841		#[document_parameters("The function to apply to the memoized value.")]
842		#[document_returns("A new `ArcLazy` instance containing the mapped value.")]
843		#[document_examples]
844		///
845		/// ```
846		/// use fp_library::{
847		/// 	classes::*,
848		/// 	types::*,
849		/// };
850		///
851		/// let memo = ArcLazy::new(|| 10);
852		/// let mapped = memo.ref_map(|x| *x * 2);
853		/// assert_eq!(*mapped.evaluate(), 20);
854		/// ```
855		#[inline]
856		pub fn ref_map<B: 'a>(
857			self,
858			f: impl FnOnce(&A) -> B + Send + 'a,
859		) -> Lazy<'a, B, ArcLazyConfig>
860		where
861			A: Send + Sync, {
862			ArcLazy::new(move || f(self.evaluate()))
863		}
864	}
865
866	/// Single-threaded memoization alias.
867	pub type RcLazy<'a, A> = Lazy<'a, A, RcLazyConfig>;
868
869	/// Thread-safe memoization alias.
870	pub type ArcLazy<'a, A> = Lazy<'a, A, ArcLazyConfig>;
871
872	impl_kind! {
873		impl<Config: LazyConfig> for LazyBrand<Config> {
874			type Of<'a, A: 'a>: 'a = Lazy<'a, A, Config>;
875		}
876	}
877
878	#[document_type_parameters(
879		"The lifetime of the computation.",
880		"The type of the computed value."
881	)]
882	impl<'a, A> Deferrable<'a> for Lazy<'a, A, RcLazyConfig>
883	where
884		A: Clone + 'a,
885	{
886		/// Defers a computation that produces a `Lazy` value.
887		///
888		/// This flattens the nested structure: instead of `Lazy<Lazy<A>>`, we get `Lazy<A>`.
889		/// The inner `Lazy` is computed only when the outer `Lazy` is evaluated.
890		#[document_signature]
891		///
892		#[document_parameters("The thunk that produces the lazy value.")]
893		///
894		#[document_returns("A new `Lazy` value.")]
895		///
896		#[document_examples]
897		///
898		/// ```
899		/// use fp_library::{
900		/// 	brands::*,
901		/// 	classes::*,
902		/// 	functions::*,
903		/// 	types::*,
904		/// };
905		///
906		/// let lazy = Lazy::<_, RcLazyConfig>::defer(|| RcLazy::pure(42));
907		/// assert_eq!(*lazy.evaluate(), 42);
908		/// ```
909		fn defer(f: impl FnOnce() -> Self + 'a) -> Self
910		where
911			Self: Sized, {
912			RcLazy::new(move || f().evaluate().clone())
913		}
914	}
915
916	#[document_type_parameters("The lifetime of the reference.", "The type of the computed value.")]
917	impl<'a, A> Deferrable<'a> for Lazy<'a, A, ArcLazyConfig>
918	where
919		A: Send + Sync + 'a,
920	{
921		/// Defers a computation that produces a thread-safe `Lazy` value.
922		///
923		/// The thunk `f` is called eagerly to obtain the inner `ArcLazy`, which is
924		/// then returned directly. The inner `ArcLazy` retains its own lazy
925		/// semantics, so the underlying computation is still deferred. This eager
926		/// call to `f` is necessary because `Deferrable::defer` does not require
927		/// `Send` on the thunk, while `ArcLazy::new` does.
928		#[document_signature]
929		///
930		#[document_parameters("The thunk that produces the lazy value.")]
931		///
932		#[document_returns("A new `ArcLazy` value.")]
933		///
934		#[document_examples]
935		///
936		/// ```
937		/// use fp_library::{
938		/// 	brands::*,
939		/// 	classes::*,
940		/// 	functions::*,
941		/// 	types::*,
942		/// };
943		///
944		/// let lazy: ArcLazy<i32> = defer(|| ArcLazy::pure(42));
945		/// assert_eq!(*lazy.evaluate(), 42);
946		/// ```
947		fn defer(f: impl FnOnce() -> Self + 'a) -> Self
948		where
949			Self: Sized, {
950			f()
951		}
952	}
953
954	#[document_type_parameters(
955		"The lifetime of the computation.",
956		"The type of the computed value."
957	)]
958	impl<'a, A> SendDeferrable<'a> for Lazy<'a, A, ArcLazyConfig>
959	where
960		A: Clone + Send + Sync + 'a,
961	{
962		/// Defers a computation that produces a thread-safe `Lazy` value using a thread-safe thunk.
963		///
964		/// This flattens the nested structure: instead of `ArcLazy<ArcLazy<A>>`, we get `ArcLazy<A>`.
965		/// The inner `Lazy` is computed only when the outer `Lazy` is evaluated.
966		#[document_signature]
967		///
968		#[document_parameters("The thunk that produces the lazy value.")]
969		///
970		#[document_returns("A new `ArcLazy` value.")]
971		///
972		#[document_examples]
973		///
974		/// ```
975		/// use fp_library::{
976		/// 	brands::*,
977		/// 	classes::*,
978		/// 	types::*,
979		/// };
980		///
981		/// let lazy = ArcLazy::send_defer(|| ArcLazy::pure(42));
982		/// assert_eq!(*lazy.evaluate(), 42);
983		/// ```
984		fn send_defer(f: impl FnOnce() -> Self + Send + 'a) -> Self
985		where
986			Self: Sized, {
987			ArcLazy::new(move || f().evaluate().clone())
988		}
989	}
990
991	impl RefFunctor for LazyBrand<RcLazyConfig> {
992		/// Maps a function over the memoized value, where the function takes a reference.
993		#[document_signature]
994		///
995		#[document_type_parameters(
996			"The lifetime of the values.",
997			"The type of the value.",
998			"The type of the result."
999		)]
1000		///
1001		#[document_parameters("The function to apply.", "The memoized value.")]
1002		///
1003		#[document_returns("A new memoized value.")]
1004		///
1005		#[document_examples]
1006		///
1007		/// ```
1008		/// use fp_library::{
1009		/// 	brands::*,
1010		/// 	classes::*,
1011		/// 	types::*,
1012		/// };
1013		///
1014		/// let memo = Lazy::<_, RcLazyConfig>::new(|| 10);
1015		/// let mapped = LazyBrand::<RcLazyConfig>::ref_map(|x: &i32| *x * 2, memo);
1016		/// assert_eq!(*mapped.evaluate(), 20);
1017		/// ```
1018		fn ref_map<'a, A: 'a, B: 'a>(
1019			f: impl FnOnce(&A) -> B + 'a,
1020			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1021		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
1022			fa.ref_map(f)
1023		}
1024	}
1025
1026	impl SendRefFunctor for LazyBrand<ArcLazyConfig> {
1027		/// Maps a thread-safe function over the memoized value, where the function takes a reference.
1028		#[document_signature]
1029		///
1030		#[document_type_parameters(
1031			"The lifetime of the values.",
1032			"The type of the value.",
1033			"The type of the result."
1034		)]
1035		///
1036		#[document_parameters("The function to apply.", "The memoized value.")]
1037		///
1038		#[document_returns("A new memoized value.")]
1039		///
1040		#[document_examples]
1041		///
1042		/// ```
1043		/// use fp_library::{
1044		/// 	brands::*,
1045		/// 	classes::*,
1046		/// 	types::*,
1047		/// };
1048		///
1049		/// let memo = ArcLazy::new(|| 10);
1050		/// let mapped = LazyBrand::<ArcLazyConfig>::send_ref_map(|x: &i32| *x * 2, memo);
1051		/// assert_eq!(*mapped.evaluate(), 20);
1052		/// ```
1053		fn send_ref_map<'a, A: Send + Sync + 'a, B: Send + Sync + 'a>(
1054			f: impl FnOnce(&A) -> B + Send + 'a,
1055			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1056		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
1057			fa.ref_map(f)
1058		}
1059	}
1060
1061	// --- Display ---
1062
1063	#[document_type_parameters(
1064		"The lifetime of the reference.",
1065		"The type of the computed value.",
1066		"The memoization configuration."
1067	)]
1068	#[document_parameters("The lazy value to display.")]
1069	impl<'a, A: fmt::Display + 'a, Config: LazyConfig> fmt::Display for Lazy<'a, A, Config> {
1070		/// Forces evaluation and displays the value.
1071		#[document_signature]
1072		///
1073		#[document_parameters("The formatter.")]
1074		///
1075		#[document_returns("The formatting result.")]
1076		///
1077		#[document_examples]
1078		///
1079		/// ```
1080		/// use fp_library::{
1081		/// 	classes::*,
1082		/// 	types::*,
1083		/// };
1084		///
1085		/// let lazy = RcLazy::new(|| 42);
1086		/// assert_eq!(format!("{}", lazy), "42");
1087		///
1088		/// let lazy = ArcLazy::new(|| 42);
1089		/// assert_eq!(format!("{}", lazy), "42");
1090		/// ```
1091		fn fmt(
1092			&self,
1093			f: &mut fmt::Formatter<'_>,
1094		) -> fmt::Result {
1095			fmt::Display::fmt(self.evaluate(), f)
1096		}
1097	}
1098
1099	// --- Semigroup ---
1100
1101	#[document_type_parameters(
1102		"The lifetime of the computation.",
1103		"The type of the computed value."
1104	)]
1105	impl<'a, A: Semigroup + Clone + 'a> Semigroup for Lazy<'a, A, RcLazyConfig> {
1106		/// Combines two `RcLazy` values by combining their results using the inner type's `Semigroup`.
1107		///
1108		/// Both sides are forced on evaluation.
1109		#[document_signature]
1110		///
1111		#[document_parameters("The first lazy value.", "The second lazy value.")]
1112		///
1113		#[document_returns("A new `RcLazy` containing the combined result.")]
1114		///
1115		#[document_examples]
1116		///
1117		/// ```
1118		/// use fp_library::{
1119		/// 	functions::*,
1120		/// 	types::*,
1121		/// };
1122		///
1123		/// let a = RcLazy::pure("Hello".to_string());
1124		/// let b = RcLazy::pure(" World".to_string());
1125		/// let c = append(a, b);
1126		/// assert_eq!(*c.evaluate(), "Hello World");
1127		/// ```
1128		fn append(
1129			a: Self,
1130			b: Self,
1131		) -> Self {
1132			RcLazy::new(move || Semigroup::append(a.evaluate().clone(), b.evaluate().clone()))
1133		}
1134	}
1135
1136	#[document_type_parameters(
1137		"The lifetime of the computation.",
1138		"The type of the computed value."
1139	)]
1140	impl<'a, A: Semigroup + Clone + Send + Sync + 'a> Semigroup for Lazy<'a, A, ArcLazyConfig> {
1141		/// Combines two `ArcLazy` values by combining their results using the inner type's `Semigroup`.
1142		///
1143		/// Both sides are forced on evaluation.
1144		#[document_signature]
1145		///
1146		#[document_parameters("The first lazy value.", "The second lazy value.")]
1147		///
1148		#[document_returns("A new `ArcLazy` containing the combined result.")]
1149		///
1150		#[document_examples]
1151		///
1152		/// ```
1153		/// use fp_library::{
1154		/// 	functions::*,
1155		/// 	types::*,
1156		/// };
1157		///
1158		/// let a = ArcLazy::pure("Hello".to_string());
1159		/// let b = ArcLazy::pure(" World".to_string());
1160		/// let c = append(a, b);
1161		/// assert_eq!(*c.evaluate(), "Hello World");
1162		/// ```
1163		fn append(
1164			a: Self,
1165			b: Self,
1166		) -> Self {
1167			ArcLazy::new(move || Semigroup::append(a.evaluate().clone(), b.evaluate().clone()))
1168		}
1169	}
1170
1171	// --- Monoid ---
1172
1173	#[document_type_parameters(
1174		"The lifetime of the computation.",
1175		"The type of the computed value."
1176	)]
1177	impl<'a, A: Monoid + Clone + 'a> Monoid for Lazy<'a, A, RcLazyConfig> {
1178		/// Returns the identity `RcLazy`.
1179		#[document_signature]
1180		///
1181		#[document_returns("An `RcLazy` producing the identity value of `A`.")]
1182		///
1183		#[document_examples]
1184		///
1185		/// ```
1186		/// use fp_library::{
1187		/// 	functions::*,
1188		/// 	types::*,
1189		/// };
1190		///
1191		/// let t: RcLazy<String> = empty();
1192		/// assert_eq!(*t.evaluate(), "");
1193		/// ```
1194		fn empty() -> Self {
1195			RcLazy::new(|| Monoid::empty())
1196		}
1197	}
1198
1199	#[document_type_parameters(
1200		"The lifetime of the computation.",
1201		"The type of the computed value."
1202	)]
1203	impl<'a, A: Monoid + Clone + Send + Sync + 'a> Monoid for Lazy<'a, A, ArcLazyConfig> {
1204		/// Returns the identity `ArcLazy`.
1205		#[document_signature]
1206		///
1207		#[document_returns("An `ArcLazy` producing the identity value of `A`.")]
1208		///
1209		#[document_examples]
1210		///
1211		/// ```
1212		/// use fp_library::{
1213		/// 	functions::*,
1214		/// 	types::*,
1215		/// };
1216		///
1217		/// let t: ArcLazy<String> = empty();
1218		/// assert_eq!(*t.evaluate(), "");
1219		/// ```
1220		fn empty() -> Self {
1221			ArcLazy::new(|| Monoid::empty())
1222		}
1223	}
1224
1225	// --- Hash ---
1226
1227	#[document_type_parameters(
1228		"The lifetime of the reference.",
1229		"The type of the computed value.",
1230		"The memoization configuration."
1231	)]
1232	#[document_parameters("The lazy value to hash.")]
1233	impl<'a, A: Hash + 'a, Config: LazyConfig> Hash for Lazy<'a, A, Config> {
1234		/// Forces evaluation and hashes the value.
1235		#[document_signature]
1236		#[document_type_parameters("The type of the hasher.")]
1237		///
1238		#[document_parameters("The hasher state.")]
1239		///
1240		#[document_examples]
1241		///
1242		/// ```
1243		/// use {
1244		/// 	fp_library::types::*,
1245		/// 	std::{
1246		/// 		collections::hash_map::DefaultHasher,
1247		/// 		hash::{
1248		/// 			Hash,
1249		/// 			Hasher,
1250		/// 		},
1251		/// 	},
1252		/// };
1253		///
1254		/// let lazy = RcLazy::new(|| 42);
1255		/// let mut hasher = DefaultHasher::new();
1256		/// lazy.hash(&mut hasher);
1257		/// let h1 = hasher.finish();
1258		///
1259		/// let mut hasher = DefaultHasher::new();
1260		/// 42i32.hash(&mut hasher);
1261		/// let h2 = hasher.finish();
1262		///
1263		/// assert_eq!(h1, h2);
1264		///
1265		/// let lazy = ArcLazy::new(|| 42);
1266		/// let mut hasher = DefaultHasher::new();
1267		/// lazy.hash(&mut hasher);
1268		/// let h3 = hasher.finish();
1269		///
1270		/// assert_eq!(h1, h3);
1271		/// ```
1272		fn hash<H: Hasher>(
1273			&self,
1274			state: &mut H,
1275		) {
1276			self.evaluate().hash(state)
1277		}
1278	}
1279
1280	// --- Foldable ---
1281
1282	#[document_type_parameters("The memoization configuration (determines Rc vs Arc).")]
1283	impl<Config: LazyConfig> Foldable for LazyBrand<Config> {
1284		/// Folds the `Lazy` from the right.
1285		///
1286		/// Forces evaluation and folds the single contained value.
1287		#[document_signature]
1288		///
1289		#[document_type_parameters(
1290			"The lifetime of the computation.",
1291			"The brand of the cloneable function to use.",
1292			"The type of the elements in the structure.",
1293			"The type of the accumulator."
1294		)]
1295		///
1296		#[document_parameters(
1297			"The function to apply to each element and the accumulator.",
1298			"The initial value of the accumulator.",
1299			"The `Lazy` to fold."
1300		)]
1301		///
1302		#[document_returns("The final accumulator value.")]
1303		#[document_examples]
1304		///
1305		/// ```
1306		/// use fp_library::{
1307		/// 	brands::*,
1308		/// 	functions::*,
1309		/// 	types::*,
1310		/// };
1311		///
1312		/// let lazy = RcLazy::new(|| 10);
1313		/// let result = fold_right::<RcFnBrand, LazyBrand<RcLazyConfig>, _, _>(|a, b| a + b, 5, lazy);
1314		/// assert_eq!(result, 15);
1315		/// ```
1316		fn fold_right<'a, FnBrand, A: 'a + Clone, B: 'a>(
1317			func: impl Fn(A, B) -> B + 'a,
1318			initial: B,
1319			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1320		) -> B
1321		where
1322			FnBrand: CloneableFn + 'a, {
1323			func(fa.evaluate().clone(), initial)
1324		}
1325
1326		/// Folds the `Lazy` from the left.
1327		///
1328		/// Forces evaluation and folds the single contained value.
1329		#[document_signature]
1330		///
1331		#[document_type_parameters(
1332			"The lifetime of the computation.",
1333			"The brand of the cloneable function to use.",
1334			"The type of the elements in the structure.",
1335			"The type of the accumulator."
1336		)]
1337		///
1338		#[document_parameters(
1339			"The function to apply to the accumulator and each element.",
1340			"The initial value of the accumulator.",
1341			"The `Lazy` to fold."
1342		)]
1343		///
1344		#[document_returns("The final accumulator value.")]
1345		#[document_examples]
1346		///
1347		/// ```
1348		/// use fp_library::{
1349		/// 	brands::*,
1350		/// 	functions::*,
1351		/// 	types::*,
1352		/// };
1353		///
1354		/// let lazy = RcLazy::new(|| 10);
1355		/// let result = fold_left::<RcFnBrand, LazyBrand<RcLazyConfig>, _, _>(|b, a| b + a, 5, lazy);
1356		/// assert_eq!(result, 15);
1357		/// ```
1358		fn fold_left<'a, FnBrand, A: 'a + Clone, B: 'a>(
1359			func: impl Fn(B, A) -> B + 'a,
1360			initial: B,
1361			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1362		) -> B
1363		where
1364			FnBrand: CloneableFn + 'a, {
1365			func(initial, fa.evaluate().clone())
1366		}
1367
1368		/// Maps the value to a monoid and returns it.
1369		///
1370		/// Forces evaluation and maps the single contained value.
1371		#[document_signature]
1372		///
1373		#[document_type_parameters(
1374			"The lifetime of the computation.",
1375			"The brand of the cloneable function to use.",
1376			"The type of the elements in the structure.",
1377			"The type of the monoid."
1378		)]
1379		///
1380		#[document_parameters("The mapping function.", "The Lazy to fold.")]
1381		///
1382		#[document_returns("The monoid value.")]
1383		#[document_examples]
1384		///
1385		/// ```
1386		/// use fp_library::{
1387		/// 	brands::*,
1388		/// 	functions::*,
1389		/// 	types::*,
1390		/// };
1391		///
1392		/// let lazy = RcLazy::new(|| 10);
1393		/// let result =
1394		/// 	fold_map::<RcFnBrand, LazyBrand<RcLazyConfig>, _, String>(|a: i32| a.to_string(), lazy);
1395		/// assert_eq!(result, "10");
1396		/// ```
1397		fn fold_map<'a, FnBrand, A: 'a + Clone, R: Monoid>(
1398			func: impl Fn(A) -> R + 'a,
1399			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1400		) -> R
1401		where
1402			FnBrand: CloneableFn + 'a, {
1403			func(fa.evaluate().clone())
1404		}
1405	}
1406
1407	// --- WithIndex ---
1408
1409	#[document_type_parameters("The memoization configuration (determines Rc vs Arc).")]
1410	impl<Config: LazyConfig> WithIndex for LazyBrand<Config> {
1411		type Index = ();
1412	}
1413
1414	// --- FoldableWithIndex ---
1415
1416	#[document_type_parameters("The memoization configuration (determines Rc vs Arc).")]
1417	impl<Config: LazyConfig> FoldableWithIndex for LazyBrand<Config> {
1418		/// Folds the `Lazy` using a monoid, providing the index `()`.
1419		///
1420		/// Forces evaluation and maps the single contained value with the unit index.
1421		#[document_signature]
1422		///
1423		#[document_type_parameters(
1424			"The lifetime of the computation.",
1425			"The type of the computed value.",
1426			"The monoid type."
1427		)]
1428		///
1429		#[document_parameters(
1430			"The function to apply to the index and the value.",
1431			"The `Lazy` to fold."
1432		)]
1433		///
1434		#[document_returns("The monoid value.")]
1435		#[document_examples]
1436		///
1437		/// ```
1438		/// use fp_library::{
1439		/// 	brands::*,
1440		/// 	classes::foldable_with_index::FoldableWithIndex,
1441		/// 	types::*,
1442		/// };
1443		///
1444		/// let lazy = RcLazy::new(|| 10);
1445		/// let result = <LazyBrand<RcLazyConfig> as FoldableWithIndex>::fold_map_with_index(
1446		/// 	|_, x: i32| x.to_string(),
1447		/// 	lazy,
1448		/// );
1449		/// assert_eq!(result, "10");
1450		/// ```
1451		fn fold_map_with_index<'a, A: 'a + Clone, R: Monoid>(
1452			f: impl Fn((), A) -> R + 'a,
1453			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1454		) -> R {
1455			f((), fa.evaluate().clone())
1456		}
1457	}
1458
1459	// --- PartialEq ---
1460
1461	#[document_type_parameters(
1462		"The lifetime of the computation.",
1463		"The type of the computed value.",
1464		"The memoization configuration."
1465	)]
1466	#[document_parameters("The lazy value to compare.")]
1467	impl<'a, A: PartialEq + 'a, Config: LazyConfig> PartialEq for Lazy<'a, A, Config> {
1468		/// Compares two `Lazy` values for equality by forcing evaluation of both sides.
1469		///
1470		/// Note: This will trigger computation if either value has not yet been evaluated.
1471		#[document_signature]
1472		#[document_parameters("The other lazy value to compare with.")]
1473		#[document_returns("`true` if the evaluated values are equal.")]
1474		#[document_examples]
1475		///
1476		/// ```
1477		/// use fp_library::{
1478		/// 	classes::*,
1479		/// 	types::*,
1480		/// };
1481		///
1482		/// let a = RcLazy::pure(42);
1483		/// let b = RcLazy::pure(42);
1484		/// assert!(a == b);
1485		/// ```
1486		fn eq(
1487			&self,
1488			other: &Self,
1489		) -> bool {
1490			self.evaluate() == other.evaluate()
1491		}
1492	}
1493
1494	// --- PartialOrd ---
1495
1496	#[document_type_parameters(
1497		"The lifetime of the computation.",
1498		"The type of the computed value.",
1499		"The memoization configuration."
1500	)]
1501	#[document_parameters("The lazy value to compare.")]
1502	impl<'a, A: PartialOrd + 'a, Config: LazyConfig> PartialOrd for Lazy<'a, A, Config> {
1503		/// Compares two `Lazy` values for ordering by forcing evaluation of both sides.
1504		///
1505		/// Note: This will trigger computation if either value has not yet been evaluated.
1506		#[document_signature]
1507		#[document_parameters("The other lazy value to compare with.")]
1508		#[document_returns(
1509			"The ordering between the evaluated values, or `None` if not comparable."
1510		)]
1511		#[document_examples]
1512		///
1513		/// ```
1514		/// use fp_library::{
1515		/// 	classes::*,
1516		/// 	types::*,
1517		/// };
1518		///
1519		/// let a = RcLazy::pure(1);
1520		/// let b = RcLazy::pure(2);
1521		/// assert!(a < b);
1522		/// ```
1523		fn partial_cmp(
1524			&self,
1525			other: &Self,
1526		) -> Option<std::cmp::Ordering> {
1527			self.evaluate().partial_cmp(other.evaluate())
1528		}
1529	}
1530
1531	// --- Eq ---
1532
1533	#[document_type_parameters(
1534		"The lifetime of the computation.",
1535		"The type of the computed value.",
1536		"The memoization configuration."
1537	)]
1538	impl<'a, A: Eq + 'a, Config: LazyConfig> Eq for Lazy<'a, A, Config> {}
1539
1540	// --- Ord ---
1541
1542	#[document_type_parameters(
1543		"The lifetime of the computation.",
1544		"The type of the computed value.",
1545		"The memoization configuration."
1546	)]
1547	#[document_parameters("The lazy value to compare.")]
1548	impl<'a, A: Ord + 'a, Config: LazyConfig> Ord for Lazy<'a, A, Config> {
1549		/// Compares two `Lazy` values for ordering by forcing evaluation of both sides.
1550		///
1551		/// Note: This will trigger computation if either value has not yet been evaluated.
1552		#[document_signature]
1553		#[document_parameters("The other lazy value to compare with.")]
1554		#[document_returns("The ordering between the evaluated values.")]
1555		#[document_examples]
1556		///
1557		/// ```
1558		/// use fp_library::{
1559		/// 	classes::*,
1560		/// 	types::*,
1561		/// };
1562		///
1563		/// let a = RcLazy::pure(1);
1564		/// let b = RcLazy::pure(2);
1565		/// assert_eq!(a.cmp(&b), std::cmp::Ordering::Less);
1566		/// ```
1567		fn cmp(
1568			&self,
1569			other: &Self,
1570		) -> std::cmp::Ordering {
1571			self.evaluate().cmp(other.evaluate())
1572		}
1573	}
1574
1575	#[document_type_parameters(
1576		"The lifetime of the computation.",
1577		"The type of the computed value.",
1578		"The memoization configuration."
1579	)]
1580	#[document_parameters("The lazy value to format.")]
1581	impl<'a, A, Config: LazyConfig> fmt::Debug for Lazy<'a, A, Config>
1582	where
1583		A: 'a,
1584	{
1585		/// Formats the lazy value without evaluating it.
1586		#[document_signature]
1587		#[document_parameters("The formatter.")]
1588		#[document_returns("The formatting result.")]
1589		#[document_examples]
1590		///
1591		/// ```
1592		/// use fp_library::{
1593		/// 	classes::*,
1594		/// 	types::*,
1595		/// };
1596		/// let lazy = Lazy::<_, RcLazyConfig>::pure(42);
1597		/// assert_eq!(format!("{:?}", lazy), "Lazy(..)");
1598		/// ```
1599		fn fmt(
1600			&self,
1601			f: &mut fmt::Formatter<'_>,
1602		) -> fmt::Result {
1603			f.write_str("Lazy(..)")
1604		}
1605	}
1606
1607	// --- Fix combinators ---
1608
1609	/// Computes a fixed point for `RcLazy`.
1610	///
1611	/// Constructs a self-referential `RcLazy` where the initializer receives a clone
1612	/// of the resulting lazy cell. This enables recursive definitions where the value
1613	/// depends on the lazy cell itself.
1614	///
1615	/// # Caveats
1616	///
1617	/// **Panic on reentrant evaluation:** Forcing the self-reference inside `f` before
1618	/// the outer cell has completed initialization causes a panic, because `LazyCell`
1619	/// detects the reentrant access.
1620	#[document_signature]
1621	///
1622	#[document_type_parameters(
1623		"The lifetime of the computation.",
1624		"The type of the computed value."
1625	)]
1626	///
1627	#[document_parameters(
1628		"The function that receives a lazy self-reference and produces the value."
1629	)]
1630	///
1631	#[document_returns("A new `RcLazy` instance.")]
1632	///
1633	#[document_examples]
1634	///
1635	/// ```
1636	/// use fp_library::types::{
1637	/// 	lazy::rc_lazy_fix,
1638	/// 	*,
1639	/// };
1640	///
1641	/// let lazy = rc_lazy_fix(|_self_ref: RcLazy<i32>| 42);
1642	/// assert_eq!(*lazy.evaluate(), 42);
1643	/// ```
1644	pub fn rc_lazy_fix<'a, A: Clone + 'a>(
1645		f: impl FnOnce(RcLazy<'a, A>) -> A + 'a
1646	) -> RcLazy<'a, A> {
1647		use std::{
1648			cell::OnceCell,
1649			rc::Weak,
1650		};
1651
1652		#[allow(clippy::type_complexity)]
1653		let cell: Rc<OnceCell<Weak<LazyCell<A, Box<dyn FnOnce() -> A + 'a>>>>> = Rc::new(OnceCell::new());
1654		let cell_clone = cell.clone();
1655		let lazy = RcLazy::new(move || {
1656			// INVARIANT: cell is always set on the line after this closure is
1657			// created, and the outer RcLazy is still alive (we are inside its
1658			// evaluation), so the Weak upgrade always succeeds.
1659			#[allow(clippy::expect_used)]
1660			let weak = cell_clone.get().expect("rc_lazy_fix: cell not initialized");
1661			#[allow(clippy::expect_used)]
1662			let self_ref = Lazy(weak.upgrade().expect("rc_lazy_fix: outer lazy was dropped"));
1663			f(self_ref)
1664		});
1665		let _ = cell.set(Rc::downgrade(&lazy.0));
1666		lazy
1667	}
1668
1669	/// Computes a fixed point for `ArcLazy`.
1670	///
1671	/// Constructs a self-referential `ArcLazy` where the initializer receives a clone
1672	/// of the resulting lazy cell. This enables recursive definitions where the value
1673	/// depends on the lazy cell itself.
1674	///
1675	/// # Caveats
1676	///
1677	/// **Deadlock on reentrant evaluation:** Forcing the self-reference inside `f` before
1678	/// the outer cell has completed initialization causes a deadlock, because `LazyLock`
1679	/// blocks on the lock that the current thread already holds.
1680	#[document_signature]
1681	///
1682	#[document_type_parameters(
1683		"The lifetime of the computation.",
1684		"The type of the computed value."
1685	)]
1686	///
1687	#[document_parameters(
1688		"The function that receives a lazy self-reference and produces the value."
1689	)]
1690	///
1691	#[document_returns("A new `ArcLazy` instance.")]
1692	///
1693	#[document_examples]
1694	///
1695	/// ```
1696	/// use fp_library::types::{
1697	/// 	lazy::arc_lazy_fix,
1698	/// 	*,
1699	/// };
1700	///
1701	/// let lazy = arc_lazy_fix(|_self_ref: ArcLazy<i32>| 42);
1702	/// assert_eq!(*lazy.evaluate(), 42);
1703	/// ```
1704	pub fn arc_lazy_fix<'a, A: Clone + Send + Sync + 'a>(
1705		f: impl FnOnce(ArcLazy<'a, A>) -> A + Send + 'a
1706	) -> ArcLazy<'a, A> {
1707		use std::sync::{
1708			OnceLock,
1709			Weak,
1710		};
1711
1712		#[allow(clippy::type_complexity)]
1713		let cell: Arc<OnceLock<Weak<LazyLock<A, Box<dyn FnOnce() -> A + Send + 'a>>>>> =
1714			Arc::new(OnceLock::new());
1715		let cell_clone = cell.clone();
1716		let lazy = ArcLazy::new(move || {
1717			// INVARIANT: cell is always set on the line after this closure is
1718			// created, and the outer ArcLazy is still alive (we are inside its
1719			// evaluation), so the Weak upgrade always succeeds.
1720			#[allow(clippy::expect_used)]
1721			let weak = cell_clone.get().expect("arc_lazy_fix: cell not initialized");
1722			#[allow(clippy::expect_used)]
1723			let self_ref = Lazy(weak.upgrade().expect("arc_lazy_fix: outer lazy was dropped"));
1724			f(self_ref)
1725		});
1726		let _ = cell.set(Arc::downgrade(&lazy.0));
1727		lazy
1728	}
1729}
1730
1731pub use inner::*;
1732
1733#[cfg(test)]
1734mod tests {
1735	use {
1736		super::inner::*,
1737		crate::types::{
1738			Thunk,
1739			Trampoline,
1740		},
1741		quickcheck_macros::quickcheck,
1742		std::{
1743			cell::RefCell,
1744			rc::Rc,
1745			sync::Arc,
1746		},
1747	};
1748
1749	/// Tests that `Lazy` caches the result of the computation.
1750	///
1751	/// Verifies that the initializer is called only once.
1752	#[test]
1753	fn test_memo_caching() {
1754		let counter = Rc::new(RefCell::new(0));
1755		let counter_clone = counter.clone();
1756		let memo = RcLazy::new(move || {
1757			*counter_clone.borrow_mut() += 1;
1758			42
1759		});
1760
1761		assert_eq!(*counter.borrow(), 0);
1762		assert_eq!(*memo.evaluate(), 42);
1763		assert_eq!(*counter.borrow(), 1);
1764		assert_eq!(*memo.evaluate(), 42);
1765		assert_eq!(*counter.borrow(), 1);
1766	}
1767
1768	/// Tests that `Lazy` shares the cache across clones.
1769	///
1770	/// Verifies that clones see the same value and don't recompute.
1771	#[test]
1772	fn test_memo_sharing() {
1773		let counter = Rc::new(RefCell::new(0));
1774		let counter_clone = counter.clone();
1775		let memo = RcLazy::new(move || {
1776			*counter_clone.borrow_mut() += 1;
1777			42
1778		});
1779		let shared = memo.clone();
1780
1781		assert_eq!(*memo.evaluate(), 42);
1782		assert_eq!(*counter.borrow(), 1);
1783		assert_eq!(*shared.evaluate(), 42);
1784		assert_eq!(*counter.borrow(), 1);
1785	}
1786
1787	/// Tests thread safety of `ArcLazy`.
1788	///
1789	/// Verifies that `ArcLazy` can be shared across threads and computes only once.
1790	#[test]
1791	fn test_arc_memo_thread_safety() {
1792		use std::{
1793			sync::atomic::{
1794				AtomicUsize,
1795				Ordering,
1796			},
1797			thread,
1798		};
1799
1800		let counter = Arc::new(AtomicUsize::new(0));
1801		let counter_clone = counter.clone();
1802		let memo = ArcLazy::new(move || {
1803			counter_clone.fetch_add(1, Ordering::SeqCst);
1804			42
1805		});
1806
1807		let mut handles = vec![];
1808		for _ in 0 .. 10 {
1809			let memo_clone = memo.clone();
1810			handles.push(thread::spawn(move || {
1811				assert_eq!(*memo_clone.evaluate(), 42);
1812			}));
1813		}
1814
1815		for handle in handles {
1816			handle.join().unwrap();
1817		}
1818
1819		assert_eq!(counter.load(Ordering::SeqCst), 1);
1820	}
1821
1822	/// Tests creation from `Thunk`.
1823	///
1824	/// Verifies `From<Thunk>` works correctly.
1825	#[test]
1826	fn test_memo_from_eval() {
1827		let eval = Thunk::new(|| 42);
1828		let memo = RcLazy::from(eval);
1829		assert_eq!(*memo.evaluate(), 42);
1830	}
1831
1832	/// Tests creation from `Trampoline`.
1833	///
1834	/// Verifies `From<Trampoline>` works correctly.
1835	#[test]
1836	fn test_memo_from_task() {
1837		// Trampoline requires 'static due to type erasure via Box<dyn Any>
1838		let task = Trampoline::pure(42);
1839		let memo = RcLazy::from(task);
1840		assert_eq!(*memo.evaluate(), 42);
1841	}
1842
1843	/// Tests conversion from `RcLazy` to `ArcLazy`.
1844	///
1845	/// Verifies `From<RcLazy>` for `ArcLazy` works correctly.
1846	#[test]
1847	fn test_rc_lazy_to_arc_lazy() {
1848		let rc = RcLazy::new(|| "hello".to_string());
1849		let arc: ArcLazy<String> = ArcLazy::from(rc);
1850		assert_eq!(*arc.evaluate(), "hello");
1851	}
1852
1853	/// Tests conversion from `ArcLazy` to `RcLazy`.
1854	///
1855	/// Verifies `From<ArcLazy>` for `RcLazy` works correctly.
1856	#[test]
1857	fn test_arc_lazy_to_rc_lazy() {
1858		let arc = ArcLazy::new(|| "world".to_string());
1859		let rc: RcLazy<String> = RcLazy::from(arc);
1860		assert_eq!(*rc.evaluate(), "world");
1861	}
1862
1863	/// Tests that `RcLazy` to `ArcLazy` conversion eagerly evaluates.
1864	///
1865	/// Verifies that the source is evaluated during conversion, not deferred.
1866	#[test]
1867	fn test_rc_to_arc_eager_evaluation() {
1868		let counter = Rc::new(RefCell::new(0));
1869		let counter_clone = counter.clone();
1870		let rc = RcLazy::new(move || {
1871			*counter_clone.borrow_mut() += 1;
1872			99
1873		});
1874		assert_eq!(*counter.borrow(), 0);
1875
1876		let arc: ArcLazy<i32> = ArcLazy::from(rc);
1877		// Conversion should have forced evaluation.
1878		assert_eq!(*counter.borrow(), 1);
1879		assert_eq!(*arc.evaluate(), 99);
1880		// No additional evaluation.
1881		assert_eq!(*counter.borrow(), 1);
1882	}
1883
1884	/// Tests that `ArcLazy` to `RcLazy` conversion eagerly evaluates.
1885	///
1886	/// Verifies that the source is evaluated during conversion, not deferred.
1887	#[test]
1888	fn test_arc_to_rc_eager_evaluation() {
1889		use std::sync::atomic::{
1890			AtomicUsize,
1891			Ordering,
1892		};
1893
1894		let counter = Arc::new(AtomicUsize::new(0));
1895		let counter_clone = counter.clone();
1896		let arc = ArcLazy::new(move || {
1897			counter_clone.fetch_add(1, Ordering::SeqCst);
1898			77
1899		});
1900		assert_eq!(counter.load(Ordering::SeqCst), 0);
1901
1902		let rc: RcLazy<i32> = RcLazy::from(arc);
1903		// Conversion should have forced evaluation.
1904		assert_eq!(counter.load(Ordering::SeqCst), 1);
1905		assert_eq!(*rc.evaluate(), 77);
1906		// No additional evaluation.
1907		assert_eq!(counter.load(Ordering::SeqCst), 1);
1908	}
1909
1910	/// Property: RcLazy to ArcLazy round-trip preserves values.
1911	#[quickcheck]
1912	fn prop_rc_to_arc_preserves_value(x: i32) -> bool {
1913		let rc = RcLazy::new(move || x);
1914		let arc: ArcLazy<i32> = ArcLazy::from(rc);
1915		*arc.evaluate() == x
1916	}
1917
1918	/// Property: ArcLazy to RcLazy round-trip preserves values.
1919	#[quickcheck]
1920	fn prop_arc_to_rc_preserves_value(x: i32) -> bool {
1921		let arc = ArcLazy::new(move || x);
1922		let rc: RcLazy<i32> = RcLazy::from(arc);
1923		*rc.evaluate() == x
1924	}
1925
1926	/// Tests Defer implementation.
1927	#[test]
1928	fn test_defer() {
1929		use crate::classes::deferrable::defer;
1930
1931		let memo: RcLazy<i32> = defer(|| RcLazy::new(|| 42));
1932		assert_eq!(*memo.evaluate(), 42);
1933	}
1934
1935	/// Tests SendDefer implementation.
1936	#[test]
1937	fn test_send_defer() {
1938		use crate::classes::send_deferrable::send_defer;
1939
1940		let memo: ArcLazy<i32> = send_defer(|| ArcLazy::new(|| 42));
1941		assert_eq!(*memo.evaluate(), 42);
1942	}
1943
1944	/// Tests `RcLazy::pure`.
1945	///
1946	/// Verifies that `pure` creates a lazy value from a pre-computed value.
1947	#[test]
1948	fn test_rc_lazy_pure() {
1949		let lazy = RcLazy::pure(42);
1950		assert_eq!(*lazy.evaluate(), 42);
1951
1952		// Verify it's still lazy (shares cache)
1953		let shared = lazy.clone();
1954		assert_eq!(*shared.evaluate(), 42);
1955	}
1956
1957	/// Tests `ArcLazy::pure`.
1958	///
1959	/// Verifies that `pure` creates a thread-safe lazy value from a pre-computed value.
1960	#[test]
1961	fn test_arc_lazy_pure() {
1962		let lazy = ArcLazy::pure(42);
1963		assert_eq!(*lazy.evaluate(), 42);
1964
1965		// Verify it's still lazy (shares cache)
1966		let shared = lazy.clone();
1967		assert_eq!(*shared.evaluate(), 42);
1968	}
1969
1970	/// Tests `ArcLazy::pure` with thread safety.
1971	///
1972	/// Verifies that `pure` works across threads.
1973	#[test]
1974	fn test_arc_lazy_pure_thread_safety() {
1975		use std::thread;
1976
1977		let lazy = ArcLazy::pure(42);
1978
1979		let mut handles = vec![];
1980		for _ in 0 .. 10 {
1981			let lazy_clone = lazy.clone();
1982			handles.push(thread::spawn(move || {
1983				assert_eq!(*lazy_clone.evaluate(), 42);
1984			}));
1985		}
1986
1987		for handle in handles {
1988			handle.join().unwrap();
1989		}
1990	}
1991
1992	// Memoization Properties
1993
1994	/// Property: getting a memoized value twice returns the same result (Rc).
1995	#[quickcheck]
1996	fn prop_rc_memo_get_memoization(x: i32) -> bool {
1997		let memo = RcLazy::new(move || x.wrapping_mul(2));
1998		let result1 = *memo.evaluate();
1999		let result2 = *memo.evaluate();
2000		result1 == result2
2001	}
2002
2003	/// Property: getting a memoized value twice returns the same result (Arc).
2004	#[quickcheck]
2005	fn prop_arc_memo_get_memoization(x: i32) -> bool {
2006		let memo = ArcLazy::new(move || x.wrapping_mul(2));
2007		let result1 = *memo.evaluate();
2008		let result2 = *memo.evaluate();
2009		result1 == result2
2010	}
2011
2012	// Clone Equivalence Properties
2013
2014	/// Property: cloning an RcLazy shares state.
2015	#[quickcheck]
2016	fn prop_rc_memo_clone_shares_state(x: i32) -> bool {
2017		let memo1 = RcLazy::new(move || x);
2018		let memo2 = memo1.clone();
2019
2020		let result1 = *memo1.evaluate();
2021		let result2 = *memo2.evaluate();
2022		result1 == result2
2023	}
2024
2025	/// Property: cloning an ArcLazy shares state.
2026	#[quickcheck]
2027	fn prop_arc_memo_clone_shares_state(x: i32) -> bool {
2028		let memo1 = ArcLazy::new(move || x);
2029		let memo2 = memo1.clone();
2030
2031		let result1 = *memo1.evaluate();
2032		let result2 = *memo2.evaluate();
2033		result1 == result2
2034	}
2035
2036	/// Property: getting original then clone gives same result.
2037	#[quickcheck]
2038	fn prop_memo_get_original_then_clone(x: String) -> bool {
2039		let value = x.clone();
2040		let memo = RcLazy::new(move || value.clone());
2041		let memo_clone = memo.clone();
2042
2043		let result1 = memo.evaluate().clone();
2044		let result2 = memo_clone.evaluate().clone();
2045
2046		result1 == result2
2047	}
2048
2049	// Determinism Properties
2050
2051	/// Property: lazy computation is deterministic.
2052	#[quickcheck]
2053	fn prop_memo_deterministic(
2054		x: i32,
2055		y: i32,
2056	) -> bool {
2057		let memo1 = RcLazy::new(move || x.wrapping_add(y));
2058		let memo2 = RcLazy::new(move || x.wrapping_add(y));
2059
2060		*memo1.evaluate() == *memo2.evaluate()
2061	}
2062
2063	// --- Tests for ArcLazy::ref_map ---
2064
2065	/// Tests `ArcLazy::ref_map`.
2066	///
2067	/// Verifies that `ref_map` applies a function to the memoized value by reference.
2068	#[test]
2069	fn test_arc_lazy_ref_map() {
2070		let memo = ArcLazy::new(|| 10);
2071		let mapped = memo.ref_map(|x| *x * 2);
2072		assert_eq!(*mapped.evaluate(), 20);
2073	}
2074
2075	/// Tests `ArcLazy::ref_map` thread safety.
2076	///
2077	/// Verifies that the mapped value can be shared across threads.
2078	#[test]
2079	fn test_arc_lazy_ref_map_thread_safety() {
2080		use std::thread;
2081
2082		let memo = ArcLazy::new(|| 10);
2083		let mapped = memo.ref_map(|x| *x * 3);
2084
2085		let mut handles = vec![];
2086		for _ in 0 .. 5 {
2087			let m = mapped.clone();
2088			handles.push(thread::spawn(move || {
2089				assert_eq!(*m.evaluate(), 30);
2090			}));
2091		}
2092
2093		for handle in handles {
2094			handle.join().unwrap();
2095		}
2096	}
2097
2098	// --- Tests for Semigroup ---
2099
2100	/// Tests the `Semigroup` implementation for `RcLazy`.
2101	///
2102	/// Verifies that `append` correctly combines two lazy values.
2103	#[test]
2104	fn test_rc_lazy_semigroup() {
2105		use crate::classes::semigroup::append;
2106
2107		let a = RcLazy::pure("Hello".to_string());
2108		let b = RcLazy::pure(" World".to_string());
2109		let c = append(a, b);
2110		assert_eq!(*c.evaluate(), "Hello World");
2111	}
2112
2113	/// Tests the `Semigroup` implementation for `ArcLazy`.
2114	///
2115	/// Verifies that `append` correctly combines two thread-safe lazy values.
2116	#[test]
2117	fn test_arc_lazy_semigroup() {
2118		use crate::classes::semigroup::append;
2119
2120		let a = ArcLazy::pure("Hello".to_string());
2121		let b = ArcLazy::pure(" World".to_string());
2122		let c = append(a, b);
2123		assert_eq!(*c.evaluate(), "Hello World");
2124	}
2125
2126	/// Tests `Semigroup` associativity for `RcLazy`.
2127	#[test]
2128	fn test_rc_lazy_semigroup_associativity() {
2129		use crate::classes::semigroup::append;
2130
2131		let a = RcLazy::pure("a".to_string());
2132		let b = RcLazy::pure("b".to_string());
2133		let c = RcLazy::pure("c".to_string());
2134
2135		let ab_c = append(append(a.clone(), b.clone()), c.clone());
2136		let a_bc = append(a, append(b, c));
2137
2138		assert_eq!(*ab_c.evaluate(), *a_bc.evaluate());
2139	}
2140
2141	// --- Tests for Monoid ---
2142
2143	/// Tests the `Monoid` implementation for `RcLazy`.
2144	///
2145	/// Verifies that `empty` returns the identity element.
2146	#[test]
2147	fn test_rc_lazy_monoid() {
2148		use crate::classes::monoid::empty;
2149
2150		let t: RcLazy<String> = empty();
2151		assert_eq!(*t.evaluate(), "");
2152	}
2153
2154	/// Tests the `Monoid` implementation for `ArcLazy`.
2155	///
2156	/// Verifies that `empty` returns the identity element.
2157	#[test]
2158	fn test_arc_lazy_monoid() {
2159		use crate::classes::monoid::empty;
2160
2161		let t: ArcLazy<String> = empty();
2162		assert_eq!(*t.evaluate(), "");
2163	}
2164
2165	/// Tests `Monoid` identity laws for `RcLazy`.
2166	#[test]
2167	fn test_rc_lazy_monoid_identity() {
2168		use crate::classes::{
2169			monoid::empty,
2170			semigroup::append,
2171		};
2172
2173		let a = RcLazy::pure("hello".to_string());
2174
2175		// Left identity: append(empty(), a) == a
2176		let left: RcLazy<String> = append(empty(), a.clone());
2177		assert_eq!(*left.evaluate(), *a.evaluate());
2178
2179		// Right identity: append(a, empty()) == a
2180		let right: RcLazy<String> = append(a.clone(), empty());
2181		assert_eq!(*right.evaluate(), *a.evaluate());
2182	}
2183
2184	// --- Tests for Foldable ---
2185
2186	/// Tests `fold_right` for `RcLazy`.
2187	#[test]
2188	fn test_rc_lazy_fold_right() {
2189		use crate::functions::*;
2190
2191		let lazy = RcLazy::pure(10);
2192		let result = fold_right::<
2193			crate::brands::RcFnBrand,
2194			crate::brands::LazyBrand<RcLazyConfig>,
2195			_,
2196			_,
2197		>(|a, b| a + b, 5, lazy);
2198		assert_eq!(result, 15);
2199	}
2200
2201	/// Tests `fold_left` for `RcLazy`.
2202	#[test]
2203	fn test_rc_lazy_fold_left() {
2204		use crate::functions::*;
2205
2206		let lazy = RcLazy::pure(10);
2207		let result = fold_left::<
2208			crate::brands::RcFnBrand,
2209			crate::brands::LazyBrand<RcLazyConfig>,
2210			_,
2211			_,
2212		>(|b, a| b + a, 5, lazy);
2213		assert_eq!(result, 15);
2214	}
2215
2216	/// Tests `fold_map` for `RcLazy`.
2217	#[test]
2218	fn test_rc_lazy_fold_map() {
2219		use crate::functions::*;
2220
2221		let lazy = RcLazy::pure(10);
2222		let result =
2223			fold_map::<crate::brands::RcFnBrand, crate::brands::LazyBrand<RcLazyConfig>, _, _>(
2224				|a: i32| a.to_string(),
2225				lazy,
2226			);
2227		assert_eq!(result, "10");
2228	}
2229
2230	// --- Tests for PartialEq ---
2231
2232	/// Tests `PartialEq` for `RcLazy`.
2233	///
2234	/// Verifies that equality comparison forces evaluation.
2235	#[test]
2236	fn test_rc_lazy_partial_eq() {
2237		let a = RcLazy::pure(42);
2238		let b = RcLazy::pure(42);
2239		let c = RcLazy::pure(99);
2240
2241		assert!(a == b);
2242		assert!(b != c);
2243	}
2244
2245	/// Tests `PartialEq` for `ArcLazy`.
2246	///
2247	/// Verifies that equality comparison forces evaluation.
2248	#[test]
2249	fn test_arc_lazy_partial_eq() {
2250		let a = ArcLazy::pure(42);
2251		let b = ArcLazy::pure(42);
2252		let c = ArcLazy::pure(99);
2253
2254		assert!(a == b);
2255		assert!(b != c);
2256	}
2257
2258	// --- Tests for PartialOrd ---
2259
2260	/// Tests `PartialOrd` for `RcLazy`.
2261	///
2262	/// Verifies that ordering comparison forces evaluation.
2263	#[test]
2264	fn test_rc_lazy_partial_ord() {
2265		let a = RcLazy::pure(1);
2266		let b = RcLazy::pure(2);
2267		let c = RcLazy::pure(2);
2268
2269		assert!(a < b);
2270		assert!(b > a);
2271		assert!(b >= c);
2272		assert!(c <= b);
2273	}
2274
2275	/// Tests `PartialOrd` for `ArcLazy`.
2276	///
2277	/// Verifies that ordering comparison forces evaluation.
2278	#[test]
2279	fn test_arc_lazy_partial_ord() {
2280		let a = ArcLazy::pure(1);
2281		let b = ArcLazy::pure(2);
2282
2283		assert!(a < b);
2284		assert!(b > a);
2285	}
2286
2287	// fix combinator tests
2288
2289	/// Tests that `rc_lazy_fix` produces the correct value when
2290	/// the function ignores the self-reference.
2291	#[test]
2292	fn test_rc_lazy_fix_constant() {
2293		let fixed = rc_lazy_fix(|_self_ref: RcLazy<i32>| 42);
2294		assert_eq!(*fixed.evaluate(), 42);
2295	}
2296
2297	/// Tests that `rc_lazy_fix` sets up the `OnceCell` before evaluation.
2298	///
2299	/// The closure inside the resulting `RcLazy` reads from the cell, so the
2300	/// cell must be populated by the time evaluation happens.
2301	#[test]
2302	fn test_rc_lazy_fix_cell_initialized() {
2303		let fixed = rc_lazy_fix(|_self_ref: RcLazy<String>| String::from("initialized"));
2304		// If the cell were not initialized, this would panic.
2305		assert_eq!(fixed.evaluate().as_str(), "initialized");
2306	}
2307
2308	/// Tests that `rc_lazy_fix` correctly threads the self-reference.
2309	///
2310	/// The function `f` receives a lazy self-reference. When `f` does not
2311	/// force it (avoiding infinite recursion), we can verify the plumbing
2312	/// by having `f` return a value derived from a closure that captures
2313	/// (but does not evaluate) the self-reference.
2314	#[test]
2315	fn test_rc_lazy_fix_self_reference_plumbing() {
2316		// f returns a value without forcing the self-reference.
2317		let fixed = rc_lazy_fix(|_self_ref: RcLazy<i32>| 7);
2318		assert_eq!(*fixed.evaluate(), 7);
2319	}
2320
2321	/// Tests that `rc_lazy_fix` memoizes the result.
2322	///
2323	/// Multiple evaluations should return the same cached value.
2324	#[test]
2325	fn test_rc_lazy_fix_memoization() {
2326		let counter = Rc::new(RefCell::new(0));
2327		let counter_clone = counter.clone();
2328		let fixed = rc_lazy_fix(move |_self_ref: RcLazy<i32>| {
2329			*counter_clone.borrow_mut() += 1;
2330			100
2331		});
2332
2333		assert_eq!(*counter.borrow(), 0);
2334		assert_eq!(*fixed.evaluate(), 100);
2335		assert_eq!(*counter.borrow(), 1);
2336		// Second evaluation should use cached value.
2337		assert_eq!(*fixed.evaluate(), 100);
2338		assert_eq!(*counter.borrow(), 1);
2339	}
2340
2341	/// Tests that `rc_lazy_fix` works with cloned results sharing the cache.
2342	#[test]
2343	fn test_rc_lazy_fix_clone_sharing() {
2344		let fixed = rc_lazy_fix(|_self_ref: RcLazy<i32>| 55);
2345		let cloned = fixed.clone();
2346		assert_eq!(*fixed.evaluate(), 55);
2347		assert_eq!(*cloned.evaluate(), 55);
2348	}
2349
2350	/// Tests that `arc_lazy_fix` produces the correct value when
2351	/// the function ignores the self-reference.
2352	#[test]
2353	fn test_arc_lazy_fix_constant() {
2354		let fixed = arc_lazy_fix(|_self_ref: ArcLazy<i32>| 42);
2355		assert_eq!(*fixed.evaluate(), 42);
2356	}
2357
2358	/// Tests that `arc_lazy_fix` sets up the `OnceLock` before evaluation.
2359	#[test]
2360	fn test_arc_lazy_fix_cell_initialized() {
2361		let fixed = arc_lazy_fix(|_self_ref: ArcLazy<String>| String::from("initialized"));
2362		// If the lock were not initialized, this would panic.
2363		assert_eq!(fixed.evaluate().as_str(), "initialized");
2364	}
2365
2366	/// Tests that `arc_lazy_fix` correctly threads the self-reference.
2367	#[test]
2368	fn test_arc_lazy_fix_self_reference_plumbing() {
2369		let fixed = arc_lazy_fix(|_self_ref: ArcLazy<i32>| 7);
2370		assert_eq!(*fixed.evaluate(), 7);
2371	}
2372
2373	/// Tests that `arc_lazy_fix` memoizes the result.
2374	#[test]
2375	fn test_arc_lazy_fix_memoization() {
2376		use std::sync::atomic::{
2377			AtomicUsize,
2378			Ordering,
2379		};
2380
2381		let counter = Arc::new(AtomicUsize::new(0));
2382		let counter_clone = counter.clone();
2383		let fixed = arc_lazy_fix(move |_self_ref: ArcLazy<i32>| {
2384			counter_clone.fetch_add(1, Ordering::SeqCst);
2385			100
2386		});
2387
2388		assert_eq!(counter.load(Ordering::SeqCst), 0);
2389		assert_eq!(*fixed.evaluate(), 100);
2390		assert_eq!(counter.load(Ordering::SeqCst), 1);
2391		// Second evaluation should use cached value.
2392		assert_eq!(*fixed.evaluate(), 100);
2393		assert_eq!(counter.load(Ordering::SeqCst), 1);
2394	}
2395
2396	// --- ArcLazy Foldable tests ---
2397
2398	/// Tests `fold_right` on `ArcLazy`.
2399	#[test]
2400	fn test_arc_lazy_fold_right() {
2401		use crate::{
2402			brands::*,
2403			functions::*,
2404		};
2405
2406		let lazy = ArcLazy::new(|| 10);
2407		let result = fold_right::<RcFnBrand, LazyBrand<ArcLazyConfig>, _, _>(|a, b| a + b, 5, lazy);
2408		assert_eq!(result, 15);
2409	}
2410
2411	/// Tests `fold_left` on `ArcLazy`.
2412	#[test]
2413	fn test_arc_lazy_fold_left() {
2414		use crate::{
2415			brands::*,
2416			functions::*,
2417		};
2418
2419		let lazy = ArcLazy::new(|| 10);
2420		let result = fold_left::<RcFnBrand, LazyBrand<ArcLazyConfig>, _, _>(|b, a| b + a, 5, lazy);
2421		assert_eq!(result, 15);
2422	}
2423
2424	/// Tests `fold_map` on `ArcLazy`.
2425	#[test]
2426	fn test_arc_lazy_fold_map() {
2427		use crate::{
2428			brands::*,
2429			functions::*,
2430		};
2431
2432		let lazy = ArcLazy::new(|| 10);
2433		let result = fold_map::<RcFnBrand, LazyBrand<ArcLazyConfig>, _, String>(
2434			|a: i32| a.to_string(),
2435			lazy,
2436		);
2437		assert_eq!(result, "10");
2438	}
2439
2440	/// Property: ArcLazy fold_right is consistent with RcLazy fold_right.
2441	#[quickcheck]
2442	fn prop_arc_lazy_fold_right(x: i32) -> bool {
2443		use crate::{
2444			brands::*,
2445			functions::*,
2446		};
2447
2448		let rc_lazy = RcLazy::new(move || x);
2449		let arc_lazy = ArcLazy::new(move || x);
2450		let rc_result =
2451			fold_right::<RcFnBrand, LazyBrand<RcLazyConfig>, _, _>(|a, b| a + b, 0, rc_lazy);
2452		let arc_result =
2453			fold_right::<RcFnBrand, LazyBrand<ArcLazyConfig>, _, _>(|a, b| a + b, 0, arc_lazy);
2454		rc_result == arc_result
2455	}
2456
2457	// --- FoldableWithIndex tests ---
2458
2459	/// Tests `fold_map_with_index` for `RcLazy`.
2460	///
2461	/// Verifies that the index is `()` and the value is folded correctly.
2462	#[test]
2463	fn test_rc_lazy_fold_map_with_index() {
2464		use crate::{
2465			brands::*,
2466			classes::foldable_with_index::FoldableWithIndex,
2467		};
2468
2469		let lazy = RcLazy::new(|| 42);
2470		let result = <LazyBrand<RcLazyConfig> as FoldableWithIndex>::fold_map_with_index(
2471			|_, x: i32| x.to_string(),
2472			lazy,
2473		);
2474		assert_eq!(result, "42");
2475	}
2476
2477	/// Tests `fold_map_with_index` for `ArcLazy`.
2478	///
2479	/// Verifies that the index is `()` and the value is folded correctly.
2480	#[test]
2481	fn test_arc_lazy_fold_map_with_index() {
2482		use crate::{
2483			brands::*,
2484			classes::foldable_with_index::FoldableWithIndex,
2485		};
2486
2487		let lazy = ArcLazy::new(|| 10);
2488		let result = <LazyBrand<ArcLazyConfig> as FoldableWithIndex>::fold_map_with_index(
2489			|_, x: i32| x.to_string(),
2490			lazy,
2491		);
2492		assert_eq!(result, "10");
2493	}
2494
2495	/// Tests compatibility of `FoldableWithIndex` with `Foldable`.
2496	///
2497	/// Verifies that `fold_map(f, fa) = fold_map_with_index(|_, a| f(a), fa)`.
2498	#[test]
2499	fn test_rc_lazy_foldable_with_index_compatibility() {
2500		use crate::{
2501			brands::*,
2502			classes::foldable_with_index::FoldableWithIndex,
2503			functions::*,
2504		};
2505
2506		let lazy1 = RcLazy::new(|| 7);
2507		let lazy2 = RcLazy::new(|| 7);
2508		let f = |a: i32| a.to_string();
2509
2510		let fold_result = fold_map::<RcFnBrand, LazyBrand<RcLazyConfig>, _, String>(f, lazy1);
2511		let fold_with_index_result =
2512			<LazyBrand<RcLazyConfig> as FoldableWithIndex>::fold_map_with_index(|_, a| f(a), lazy2);
2513		assert_eq!(fold_result, fold_with_index_result);
2514	}
2515
2516	// --- SendRefFunctor (ArcLazy ref_map) law tests ---
2517
2518	/// Property: ArcLazy ref_map identity law.
2519	///
2520	/// ref_map(|x| x.clone(), fa) should produce the same value as fa.
2521	#[quickcheck]
2522	fn prop_arc_lazy_ref_map_identity(x: i32) -> bool {
2523		let lazy = ArcLazy::new(move || x);
2524		let mapped = lazy.clone().ref_map(|a| *a);
2525		*lazy.evaluate() == *mapped.evaluate()
2526	}
2527
2528	/// Property: ArcLazy ref_map composition law.
2529	///
2530	/// ref_map(g . f, fa) == ref_map(g, ref_map(f, fa)).
2531	#[quickcheck]
2532	fn prop_arc_lazy_ref_map_composition(x: i32) -> bool {
2533		let f = |a: &i32| a.wrapping_mul(2);
2534		let g = |a: &i32| a.wrapping_add(1);
2535
2536		let lazy1 = ArcLazy::new(move || x);
2537		let composed = lazy1.ref_map(|a| g(&f(a)));
2538
2539		let lazy2 = ArcLazy::new(move || x);
2540		let chained = lazy2.ref_map(f).ref_map(g);
2541
2542		*composed.evaluate() == *chained.evaluate()
2543	}
2544
2545	/// Property: ArcLazy ref_map preserves memoization.
2546	#[quickcheck]
2547	fn prop_arc_lazy_ref_map_memoization(x: i32) -> bool {
2548		let lazy = ArcLazy::new(move || x);
2549		let mapped = lazy.ref_map(|a| a.wrapping_mul(3));
2550		let r1 = *mapped.evaluate();
2551		let r2 = *mapped.evaluate();
2552		r1 == r2
2553	}
2554
2555	// --- rc_lazy_fix / arc_lazy_fix tests ---
2556
2557	/// Tests `rc_lazy_fix` with a self-referential computation.
2558	#[test]
2559	fn test_rc_lazy_fix_self_reference() {
2560		let lazy = rc_lazy_fix(|self_ref: RcLazy<Vec<i32>>| {
2561			// The self-reference can be evaluated to get the same value.
2562			let _ = self_ref; // The self-ref is available but evaluating it here would recurse.
2563			vec![1, 2, 3]
2564		});
2565		assert_eq!(*lazy.evaluate(), vec![1, 2, 3]);
2566	}
2567
2568	/// Tests `rc_lazy_fix` where `f` uses the self-reference after initial evaluation.
2569	#[test]
2570	fn test_rc_lazy_fix_uses_self_ref() {
2571		// Create a lazy value that, when evaluated, stores its own length.
2572		let counter = Rc::new(RefCell::new(0));
2573		let counter_clone = counter.clone();
2574		let lazy = rc_lazy_fix(move |self_ref: RcLazy<i32>| {
2575			*counter_clone.borrow_mut() += 1;
2576			// We cannot evaluate self_ref during construction (would deadlock),
2577			// but we can capture it for later use in a derived value.
2578			let _ = self_ref;
2579			42
2580		});
2581		assert_eq!(*lazy.evaluate(), 42);
2582		assert_eq!(*counter.borrow(), 1);
2583		// Verify memoization: second evaluate does not re-run.
2584		assert_eq!(*lazy.evaluate(), 42);
2585		assert_eq!(*counter.borrow(), 1);
2586	}
2587
2588	/// Tests `arc_lazy_fix` with a self-referential computation.
2589	#[test]
2590	fn test_arc_lazy_fix_self_reference() {
2591		let lazy = arc_lazy_fix(|self_ref: ArcLazy<Vec<i32>>| {
2592			let _ = self_ref;
2593			vec![1, 2, 3]
2594		});
2595		assert_eq!(*lazy.evaluate(), vec![1, 2, 3]);
2596	}
2597
2598	/// Tests `arc_lazy_fix` where `f` uses the self-reference after initial evaluation.
2599	#[test]
2600	fn test_arc_lazy_fix_uses_self_ref() {
2601		use std::sync::atomic::{
2602			AtomicUsize,
2603			Ordering,
2604		};
2605
2606		let counter = Arc::new(AtomicUsize::new(0));
2607		let counter_clone = counter.clone();
2608		let lazy = arc_lazy_fix(move |self_ref: ArcLazy<i32>| {
2609			counter_clone.fetch_add(1, Ordering::SeqCst);
2610			let _ = self_ref;
2611			42
2612		});
2613		assert_eq!(*lazy.evaluate(), 42);
2614		assert_eq!(counter.load(Ordering::SeqCst), 1);
2615		// Verify memoization: second evaluate does not re-run.
2616		assert_eq!(*lazy.evaluate(), 42);
2617		assert_eq!(counter.load(Ordering::SeqCst), 1);
2618	}
2619
2620	/// Tests `arc_lazy_fix` is thread-safe.
2621	#[test]
2622	fn test_arc_lazy_fix_thread_safety() {
2623		use std::thread;
2624
2625		let lazy = arc_lazy_fix(|self_ref: ArcLazy<i32>| {
2626			let _ = self_ref;
2627			42
2628		});
2629
2630		let mut handles = vec![];
2631		for _ in 0 .. 10 {
2632			let lazy_clone = lazy.clone();
2633			handles.push(thread::spawn(move || {
2634				assert_eq!(*lazy_clone.evaluate(), 42);
2635			}));
2636		}
2637
2638		for handle in handles {
2639			handle.join().unwrap();
2640		}
2641	}
2642
2643	/// Property: `rc_lazy_fix` with a constant function produces that constant.
2644	#[quickcheck]
2645	fn prop_rc_lazy_fix_constant(x: i32) -> bool {
2646		let fixed = rc_lazy_fix(move |_: RcLazy<i32>| x);
2647		*fixed.evaluate() == x
2648	}
2649
2650	/// Property: `arc_lazy_fix` with a constant function produces that constant.
2651	#[quickcheck]
2652	fn prop_arc_lazy_fix_constant(x: i32) -> bool {
2653		let fixed = arc_lazy_fix(move |_: ArcLazy<i32>| x);
2654		*fixed.evaluate() == x
2655	}
2656
2657	// QuickCheck Law Tests
2658
2659	// RefFunctor Laws
2660
2661	/// RefFunctor identity: `ref_map(|v| v.clone(), fa)` evaluates to the same value as `fa`.
2662	#[quickcheck]
2663	fn ref_functor_identity(x: i32) -> bool {
2664		let lazy = RcLazy::pure(x);
2665		*lazy.clone().ref_map(|v| *v).evaluate() == *lazy.evaluate()
2666	}
2667
2668	/// RefFunctor composition: `ref_map(|v| f(&g(v)), fa) == ref_map(f, ref_map(g, fa))`.
2669	#[quickcheck]
2670	fn ref_functor_composition(x: i32) -> bool {
2671		let f = |a: &i32| a.wrapping_add(1);
2672		let g = |a: &i32| a.wrapping_mul(2);
2673		let lazy = RcLazy::pure(x);
2674		let lhs = *lazy.clone().ref_map(move |v| f(&g(v))).evaluate();
2675		let rhs = *lazy.ref_map(g).ref_map(f).evaluate();
2676		lhs == rhs
2677	}
2678
2679	// Deferrable Laws
2680
2681	/// Deferrable transparency: `defer(|| pure(x))` evaluates to the same value as `pure(x)`.
2682	#[quickcheck]
2683	fn deferrable_transparency(x: i32) -> bool {
2684		let lazy = RcLazy::pure(x);
2685		let deferred: RcLazy<i32> = crate::classes::Deferrable::defer(move || RcLazy::pure(x));
2686		*deferred.evaluate() == *lazy.evaluate()
2687	}
2688
2689	// Semigroup Laws
2690
2691	/// Semigroup associativity for `RcLazy`: `append(append(a, b), c) == append(a, append(b, c))`.
2692	#[quickcheck]
2693	fn rc_lazy_semigroup_associativity(
2694		a: String,
2695		b: String,
2696		c: String,
2697	) -> bool {
2698		use crate::classes::semigroup::append;
2699
2700		let la = RcLazy::pure(a.clone());
2701		let lb = RcLazy::pure(b.clone());
2702		let lc = RcLazy::pure(c.clone());
2703		let la2 = RcLazy::pure(a);
2704		let lb2 = RcLazy::pure(b);
2705		let lc2 = RcLazy::pure(c);
2706		let lhs = append(append(la, lb), lc).evaluate().clone();
2707		let rhs = append(la2, append(lb2, lc2)).evaluate().clone();
2708		lhs == rhs
2709	}
2710
2711	/// Semigroup associativity for `ArcLazy`: `append(append(a, b), c) == append(a, append(b, c))`.
2712	#[quickcheck]
2713	fn arc_lazy_semigroup_associativity(
2714		a: String,
2715		b: String,
2716		c: String,
2717	) -> bool {
2718		use crate::classes::semigroup::append;
2719
2720		let la = ArcLazy::pure(a.clone());
2721		let lb = ArcLazy::pure(b.clone());
2722		let lc = ArcLazy::pure(c.clone());
2723		let la2 = ArcLazy::pure(a);
2724		let lb2 = ArcLazy::pure(b);
2725		let lc2 = ArcLazy::pure(c);
2726		let lhs = append(append(la, lb), lc).evaluate().clone();
2727		let rhs = append(la2, append(lb2, lc2)).evaluate().clone();
2728		lhs == rhs
2729	}
2730
2731	// Monoid Laws
2732
2733	/// Monoid left identity for `RcLazy`: `append(empty(), a) == a`.
2734	#[quickcheck]
2735	fn rc_lazy_monoid_left_identity(x: String) -> bool {
2736		use crate::classes::{
2737			monoid::empty,
2738			semigroup::append,
2739		};
2740
2741		let a = RcLazy::pure(x.clone());
2742		let lhs: RcLazy<String> = append(empty(), a);
2743		*lhs.evaluate() == x
2744	}
2745
2746	/// Monoid right identity for `RcLazy`: `append(a, empty()) == a`.
2747	#[quickcheck]
2748	fn rc_lazy_monoid_right_identity(x: String) -> bool {
2749		use crate::classes::{
2750			monoid::empty,
2751			semigroup::append,
2752		};
2753
2754		let a = RcLazy::pure(x.clone());
2755		let rhs: RcLazy<String> = append(a, empty());
2756		*rhs.evaluate() == x
2757	}
2758
2759	/// Monoid left identity for `ArcLazy`: `append(empty(), a) == a`.
2760	#[quickcheck]
2761	fn arc_lazy_monoid_left_identity(x: String) -> bool {
2762		use crate::classes::{
2763			monoid::empty,
2764			semigroup::append,
2765		};
2766
2767		let a = ArcLazy::pure(x.clone());
2768		let lhs: ArcLazy<String> = append(empty(), a);
2769		*lhs.evaluate() == x
2770	}
2771
2772	/// Monoid right identity for `ArcLazy`: `append(a, empty()) == a`.
2773	#[quickcheck]
2774	fn arc_lazy_monoid_right_identity(x: String) -> bool {
2775		use crate::classes::{
2776			monoid::empty,
2777			semigroup::append,
2778		};
2779
2780		let a = ArcLazy::pure(x.clone());
2781		let rhs: ArcLazy<String> = append(a, empty());
2782		*rhs.evaluate() == x
2783	}
2784
2785	// --- Tests for LazyConfig::PointerBrand ---
2786
2787	/// Tests that `RcLazyConfig::PointerBrand` is `RcBrand`.
2788	#[test]
2789	fn test_rc_lazy_config_pointer_brand() {
2790		fn assert_brand_is_rc<C: LazyConfig<PointerBrand = crate::brands::RcBrand>>() {}
2791		assert_brand_is_rc::<RcLazyConfig>();
2792	}
2793
2794	/// Tests that `ArcLazyConfig::PointerBrand` is `ArcBrand`.
2795	#[test]
2796	fn test_arc_lazy_config_pointer_brand() {
2797		fn assert_brand_is_arc<C: LazyConfig<PointerBrand = crate::brands::ArcBrand>>() {}
2798		assert_brand_is_arc::<ArcLazyConfig>();
2799	}
2800
2801	// SC-2: Panic poisoning test for Lazy
2802
2803	/// Tests that a panicking initializer poisons the RcLazy.
2804	///
2805	/// Verifies that subsequent evaluate calls also panic after
2806	/// the initializer panics.
2807	#[test]
2808	fn test_panic_poisoning() {
2809		use std::panic;
2810
2811		let memo: RcLazy<i32> = RcLazy::new(|| {
2812			panic!("initializer panic");
2813		});
2814
2815		let result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
2816			let _ = memo.evaluate();
2817		}));
2818		assert!(result.is_err(), "First evaluate should panic");
2819
2820		let result2 = panic::catch_unwind(panic::AssertUnwindSafe(|| {
2821			let _ = memo.evaluate();
2822		}));
2823		assert!(result2.is_err(), "Second evaluate should also panic (poisoned)");
2824	}
2825
2826	/// Tests `rc_lazy_fix` where the self-reference is shared with a derived lazy.
2827	#[test]
2828	fn test_rc_lazy_fix_shared_self_ref() {
2829		let lazy = rc_lazy_fix(|self_ref: RcLazy<i32>| {
2830			// Store the self-ref for later verification that it shares the same cache.
2831			let _captured = self_ref.clone();
2832			100
2833		});
2834		assert_eq!(*lazy.evaluate(), 100);
2835		// Clone should share the same cache.
2836		let cloned = lazy.clone();
2837		assert_eq!(*cloned.evaluate(), 100);
2838	}
2839}