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