Skip to main content

fp_library/types/
const_val.rs

1//! The `Const` functor, which ignores its second type parameter.
2
3#[fp_macros::document_module]
4mod inner {
5	use {
6		crate::{
7			Apply,
8			classes::{
9				apply_first::ApplyFirst,
10				apply_second::ApplySecond,
11				cloneable_fn::CloneableFn,
12				functor::Functor,
13				lift::Lift,
14				monoid::Monoid,
15				pointed::Pointed,
16				semiapplicative::Semiapplicative,
17				semigroup::Semigroup,
18			},
19			impl_kind,
20			kinds::*,
21		},
22		fp_macros::*,
23		std::marker::PhantomData,
24	};
25
26	/// The `Const` functor.
27	///
28	/// `Const<R, A>` stores a value of type `R` and ignores the type `A`.
29	#[document_type_parameters(
30		"The lifetime of the values.",
31		"The stored type.",
32		"The ignored type."
33	)]
34	#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
35	pub struct Const<'a, R, A>(pub R, pub PhantomData<&'a A>);
36
37	#[document_type_parameters(
38		"The lifetime of the values.",
39		"The stored type.",
40		"The ignored type."
41	)]
42	impl<'a, R, A> Const<'a, R, A> {
43		/// Creates a new `Const` instance.
44		#[document_signature]
45		#[document_parameters("The value to store.")]
46		#[document_returns("A new `Const` instance.")]
47		#[document_examples]
48		///
49		/// ```
50		/// use fp_library::types::const_val::Const;
51		///
52		/// let c: Const<i32, String> = Const::new(42);
53		/// assert_eq!(c.0, 42);
54		/// ```
55		pub fn new(r: R) -> Self {
56			Const(r, PhantomData)
57		}
58	}
59
60	/// Brand for the `Const` functor.
61	pub struct ConstBrand<R>(PhantomData<R>);
62
63	impl_kind! {
64		impl<R: 'static> for ConstBrand<R> {
65			type Of<'a, A: 'a>: 'a = Const<'a, R, A>;
66		}
67	}
68
69	#[document_type_parameters("The stored type.")]
70	impl<R: 'static> Functor for ConstBrand<R> {
71		#[document_signature]
72		#[document_type_parameters(
73			"The lifetime of the values.",
74			"The input type.",
75			"The output type."
76		)]
77		#[document_parameters(
78			"The function to map (ignored).",
79			"The `Const` instance to map over."
80		)]
81		#[document_returns("A new `Const` instance with the same stored value.")]
82		#[document_examples]
83		///
84		/// ```
85		/// use fp_library::{
86		/// 	classes::functor::Functor,
87		/// 	types::const_val::{
88		/// 		Const,
89		/// 		ConstBrand,
90		/// 	},
91		/// };
92		///
93		/// let c: Const<i32, String> = Const::new(42);
94		/// let mapped = ConstBrand::map(|s: String| s.len(), c);
95		/// assert_eq!(mapped.0, 42);
96		/// ```
97		fn map<'a, A: 'a, B: 'a>(
98			_f: impl Fn(A) -> B + 'a,
99			fa: Apply!(<Self as Kind!( type Of<'b, T: 'b>: 'b; )>::Of<'a, A>),
100		) -> Apply!(<Self as Kind!( type Of<'b, T: 'b>: 'b; )>::Of<'a, B>) {
101			Const::new(fa.0)
102		}
103	}
104
105	#[document_type_parameters("The stored type.")]
106	impl<R: 'static + Semigroup> Lift for ConstBrand<R> {
107		#[document_signature]
108		#[document_type_parameters(
109			"The lifetime of the values.",
110			"The first input type.",
111			"The second input type.",
112			"The output type."
113		)]
114		#[document_parameters(
115			"The function to lift (ignored).",
116			"The first `Const` instance.",
117			"The second `Const` instance."
118		)]
119		#[document_returns("A new `Const` instance with the combined stored values.")]
120		#[document_examples]
121		///
122		/// ```
123		/// use fp_library::{
124		/// 	classes::lift::Lift,
125		/// 	types::const_val::{
126		/// 		Const,
127		/// 		ConstBrand,
128		/// 	},
129		/// };
130		///
131		/// let c1: Const<String, i32> = Const::new("Hello".to_string());
132		/// let c2: Const<String, i32> = Const::new(" World".to_string());
133		/// let lifted = ConstBrand::lift2(|a: i32, b: i32| a + b, c1, c2);
134		/// assert_eq!(lifted.0, "Hello World");
135		/// ```
136		fn lift2<'a, A, B, C>(
137			_func: impl Fn(A, B) -> C + 'a,
138			fa: Apply!(<Self as Kind!( type Of<'b, T: 'b>: 'b; )>::Of<'a, A>),
139			fb: Apply!(<Self as Kind!( type Of<'b, T: 'b>: 'b; )>::Of<'a, B>),
140		) -> Apply!(<Self as Kind!( type Of<'b, T: 'b>: 'b; )>::Of<'a, C>)
141		where
142			A: Clone + 'a,
143			B: Clone + 'a,
144			C: 'a, {
145			Const::new(R::append(fa.0, fb.0))
146		}
147	}
148
149	#[document_type_parameters("The stored type.")]
150	impl<R: 'static + Semigroup> Semiapplicative for ConstBrand<R> {
151		#[document_signature]
152		#[document_type_parameters(
153			"The lifetime of the values.",
154			"The function brand.",
155			"The input type.",
156			"The output type."
157		)]
158		#[document_parameters(
159			"The `Const` instance containing a function.",
160			"The `Const` instance containing a value."
161		)]
162		#[document_returns("A new `Const` instance with the combined stored values.")]
163		#[document_examples]
164		///
165		/// ```
166		/// use fp_library::{
167		/// 	brands::RcFnBrand,
168		/// 	classes::{
169		/// 		cloneable_fn::CloneableFn,
170		/// 		semiapplicative::Semiapplicative,
171		/// 	},
172		/// 	types::const_val::{
173		/// 		Const,
174		/// 		ConstBrand,
175		/// 	},
176		/// };
177		///
178		/// let c1 = Const::<String, _>::new("Hello".to_string());
179		/// let c2 = Const::<String, i32>::new(" World".to_string());
180		/// let applied = ConstBrand::<String>::apply::<RcFnBrand, i32, i32>(c1, c2);
181		/// assert_eq!(applied.0, "Hello World");
182		/// ```
183		fn apply<'a, FnBrand: 'a + CloneableFn, A: 'a + Clone, B: 'a>(
184			ff: Apply!(<Self as Kind!( type Of<'b, T: 'b>: 'b; )>::Of<'a, <FnBrand as CloneableFn>::Of<'a, A, B>>),
185			fa: Apply!(<Self as Kind!( type Of<'b, T: 'b>: 'b; )>::Of<'a, A>),
186		) -> Apply!(<Self as Kind!( type Of<'b, T: 'b>: 'b; )>::Of<'a, B>) {
187			Const::new(R::append(ff.0, fa.0))
188		}
189	}
190
191	#[document_type_parameters("The stored type.")]
192	impl<R: 'static + Semigroup> ApplyFirst for ConstBrand<R> {
193		#[document_signature]
194		#[document_type_parameters(
195			"The lifetime of the values.",
196			"The first type.",
197			"The second type."
198		)]
199		#[document_parameters("The first `Const` instance.", "The second `Const` instance.")]
200		#[document_returns("A new `Const` instance with the combined stored values.")]
201		#[document_examples]
202		///
203		/// ```
204		/// use fp_library::{
205		/// 	classes::apply_first::ApplyFirst,
206		/// 	types::const_val::{
207		/// 		Const,
208		/// 		ConstBrand,
209		/// 	},
210		/// };
211		///
212		/// let c1: Const<String, i32> = Const::new("Hello".to_string());
213		/// let c2: Const<String, i32> = Const::new(" World".to_string());
214		/// let applied = ConstBrand::apply_first(c1, c2);
215		/// assert_eq!(applied.0, "Hello World");
216		/// ```
217		fn apply_first<'a, A: 'a, B: 'a>(
218			fa: Apply!(<Self as Kind!( type Of<'b, T: 'b>: 'b; )>::Of<'a, A>),
219			fb: Apply!(<Self as Kind!( type Of<'b, T: 'b>: 'b; )>::Of<'a, B>),
220		) -> Apply!(<Self as Kind!( type Of<'b, T: 'b>: 'b; )>::Of<'a, A>) {
221			Const::new(R::append(fa.0, fb.0))
222		}
223	}
224
225	#[document_type_parameters("The stored type.")]
226	impl<R: 'static + Semigroup> ApplySecond for ConstBrand<R> {
227		#[document_signature]
228		#[document_type_parameters(
229			"The lifetime of the values.",
230			"The first type.",
231			"The second type."
232		)]
233		#[document_parameters("The first `Const` instance.", "The second `Const` instance.")]
234		#[document_returns("A new `Const` instance with the combined stored values.")]
235		#[document_examples]
236		///
237		/// ```
238		/// use fp_library::{
239		/// 	classes::apply_second::ApplySecond,
240		/// 	types::const_val::{
241		/// 		Const,
242		/// 		ConstBrand,
243		/// 	},
244		/// };
245		///
246		/// let c1: Const<String, i32> = Const::new("Hello".to_string());
247		/// let c2: Const<String, i32> = Const::new(" World".to_string());
248		/// let applied = ConstBrand::apply_second(c1, c2);
249		/// assert_eq!(applied.0, "Hello World");
250		/// ```
251		fn apply_second<'a, A: 'a, B: 'a>(
252			fa: Apply!(<Self as Kind!( type Of<'b, T: 'b>: 'b; )>::Of<'a, A>),
253			fb: Apply!(<Self as Kind!( type Of<'b, T: 'b>: 'b; )>::Of<'a, B>),
254		) -> Apply!(<Self as Kind!( type Of<'b, T: 'b>: 'b; )>::Of<'a, B>) {
255			Const::new(R::append(fa.0, fb.0))
256		}
257	}
258
259	#[document_type_parameters("The stored type.")]
260	impl<R: 'static + Monoid> Pointed for ConstBrand<R> {
261		#[document_signature]
262		#[document_type_parameters("The lifetime of the values.", "The type to wrap (ignored).")]
263		#[document_parameters("The value to wrap (ignored).")]
264		#[document_returns("A new `Const` instance with the empty value of the stored type.")]
265		#[document_examples]
266		///
267		/// ```
268		/// use fp_library::{
269		/// 	classes::pointed::Pointed,
270		/// 	types::const_val::{
271		/// 		Const,
272		/// 		ConstBrand,
273		/// 	},
274		/// };
275		///
276		/// let c: Const<String, i32> = ConstBrand::pure(42);
277		/// assert_eq!(c.0, "".to_string());
278		/// ```
279		fn pure<'a, A: 'a>(_a: A) -> Apply!(<Self as Kind!( type Of<'b, T: 'b>: 'b; )>::Of<'a, A>) {
280			Const::new(R::empty())
281		}
282	}
283}
284pub use inner::*;
285
286// `A` is only `PhantomData<&'a A>` - always Clone/Copy - so we only need `R: Clone`/`R: Copy`.
287impl<'a, R: Clone, A> Clone for Const<'a, R, A> {
288	fn clone(&self) -> Self {
289		Const(self.0.clone(), std::marker::PhantomData)
290	}
291}
292impl<'a, R: Copy, A> Copy for Const<'a, R, A> {}