fp_library/types/
lazy.rs

1//! Implementations for [`Lazy`], the type of lazily-computed, memoized values.
2
3use crate::{
4	classes::{
5		ClonableFn, Defer, Monoid, Once, Semigroup, clonable_fn::ApplyClonableFn, once::ApplyOnce,
6	},
7	hkt::Kind0L1T,
8};
9use core::fmt;
10use std::{
11	fmt::{Debug, Formatter},
12	hash::{Hash, Hasher},
13};
14
15/// Represents a lazily-computed, memoized value.
16pub struct Lazy<'a, OnceBrand: Once, ClonableFnBrand: ClonableFn, A: 'a>(
17	pub ApplyOnce<OnceBrand, A>,
18	pub ApplyClonableFn<'a, ClonableFnBrand, (), A>,
19);
20
21impl<'a, OnceBrand: Once, ClonableFnBrand: ClonableFn, A> Lazy<'a, OnceBrand, ClonableFnBrand, A> {
22	pub fn new(a: ApplyClonableFn<'a, ClonableFnBrand, (), A>) -> Self {
23		Self(OnceBrand::new(), a)
24	}
25
26	pub fn force(a: Self) -> A
27	where
28		A: Clone,
29	{
30		<OnceBrand as Once>::get_or_init(&a.0, move || (a.1)(())).clone()
31	}
32}
33
34impl<'a, OnceBrand: Once, ClonableFnBrand: ClonableFn, A: 'a + Clone> Clone
35	for Lazy<'a, OnceBrand, ClonableFnBrand, A>
36where
37	ApplyOnce<OnceBrand, A>: Clone,
38{
39	fn clone(&self) -> Self {
40		Self(self.0.clone(), self.1.clone())
41	}
42}
43
44impl<'a, OnceBrand: Once, ClonableFnBrand: ClonableFn, A: Debug> Debug
45	for Lazy<'a, OnceBrand, ClonableFnBrand, A>
46where
47	ApplyOnce<OnceBrand, A>: Debug,
48	ApplyClonableFn<'a, ClonableFnBrand, (), A>: Debug,
49{
50	fn fmt(
51		&self,
52		fmt: &mut Formatter<'_>,
53	) -> fmt::Result {
54		fmt.debug_tuple("Lazy").field(&self.0).field(&self.1).finish()
55	}
56}
57
58impl<'a, OnceBrand: Once, ClonableFnBrand: ClonableFn, A: Eq> Eq
59	for Lazy<'a, OnceBrand, ClonableFnBrand, A>
60where
61	ApplyOnce<OnceBrand, A>: Eq,
62	ApplyClonableFn<'a, ClonableFnBrand, (), A>: Eq,
63{
64}
65
66impl<'a, OnceBrand: Once, ClonableFnBrand: ClonableFn, A: Hash> Hash
67	for Lazy<'a, OnceBrand, ClonableFnBrand, A>
68where
69	ApplyOnce<OnceBrand, A>: Hash,
70	ApplyClonableFn<'a, ClonableFnBrand, (), A>: Hash,
71{
72	fn hash<H: Hasher>(
73		&self,
74		state: &mut H,
75	) {
76		self.0.hash(state);
77		self.1.hash(state);
78	}
79}
80
81impl<'a, OnceBrand: Once, ClonableFnBrand: ClonableFn, A: Ord> Ord
82	for Lazy<'a, OnceBrand, ClonableFnBrand, A>
83where
84	ApplyOnce<OnceBrand, A>: Ord,
85	ApplyClonableFn<'a, ClonableFnBrand, (), A>: Ord,
86{
87	fn cmp(
88		&self,
89		other: &Self,
90	) -> std::cmp::Ordering {
91		self.0.cmp(&other.0)
92	}
93}
94
95impl<'a, OnceBrand: Once, ClonableFnBrand: ClonableFn, A: PartialEq> PartialEq
96	for Lazy<'a, OnceBrand, ClonableFnBrand, A>
97where
98	ApplyOnce<OnceBrand, A>: PartialEq,
99	ApplyClonableFn<'a, ClonableFnBrand, (), A>: PartialEq,
100{
101	fn eq(
102		&self,
103		other: &Self,
104	) -> bool {
105		self.0 == other.0 && self.1 == other.1
106	}
107}
108
109impl<'a, OnceBrand: Once, ClonableFnBrand: ClonableFn, A: PartialOrd> PartialOrd
110	for Lazy<'a, OnceBrand, ClonableFnBrand, A>
111where
112	ApplyOnce<OnceBrand, A>: PartialOrd,
113	ApplyClonableFn<'a, ClonableFnBrand, (), A>: PartialOrd,
114{
115	fn partial_cmp(
116		&self,
117		other: &Self,
118	) -> Option<std::cmp::Ordering> {
119		self.0.partial_cmp(&other.0)
120	}
121}
122
123impl<'b, OnceBrand: 'b + Once, CFB: 'b + ClonableFn, A: Semigroup<'b> + Clone> Semigroup<'b>
124	for Lazy<'b, OnceBrand, CFB, A>
125where
126	ApplyOnce<OnceBrand, A>: Clone,
127{
128	fn append<'a, ClonableFnBrand: 'a + 'b + ClonableFn>(
129		a: Self
130	) -> ApplyClonableFn<'a, ClonableFnBrand, Self, Self>
131	where
132		Self: Sized,
133		'b: 'a,
134	{
135		<ClonableFnBrand as ClonableFn>::new(move |b: Self| {
136			Self::new(<CFB as ClonableFn>::new({
137				let a = a.clone();
138				move |_: ()| {
139					A::append::<ClonableFnBrand>(Lazy::force(a.clone()))(Lazy::force(b.clone()))
140				}
141			}))
142		})
143	}
144}
145
146impl<'b, OnceBrand: 'b + Once, CFB: 'b + ClonableFn, A: Monoid<'b> + Clone> Monoid<'b>
147	for Lazy<'b, OnceBrand, CFB, A>
148where
149	ApplyOnce<OnceBrand, A>: Clone,
150{
151	fn empty() -> Self {
152		Self::new(<CFB as ClonableFn>::new(move |_| <A as Monoid<'b>>::empty()))
153	}
154}
155
156impl<'a, OnceBrand: Once, CFB: ClonableFn, A: Clone> Defer<'a> for Lazy<'a, OnceBrand, CFB, A> {
157	fn defer<ClonableFnBrand: 'a + ClonableFn>(
158		f: ApplyClonableFn<'a, ClonableFnBrand, (), Self>
159	) -> Self
160	where
161		Self: Sized,
162	{
163		Self::new(<CFB as ClonableFn>::new(move |_| Lazy::<'a, OnceBrand, CFB, A>::force(f(()))))
164	}
165}
166
167pub struct LazyBrand<OnceBrand: Once, ClonableFnBrand: ClonableFn>(OnceBrand, ClonableFnBrand);
168
169// impl<OnceBrand: Once, ClonableFnBrand: ClonableFn> Kind0L1T
170// 	for LazyBrand<OnceBrand, ClonableFnBrand>
171// where
172// 	A: 'static,
173// {
174// 	type Output<A> = Lazy<'static, OnceBrand, ClonableFnBrand, A>;
175// }