fp_library/types/
identity.rs

1//! Implementations for [`Identity`], a type that wraps a value.
2
3use crate::{
4	brands::IdentityBrand,
5	classes::{
6		applicative::Applicative,
7		apply_first::ApplyFirst,
8		apply_second::ApplySecond,
9		clonable_fn::{ApplyClonableFn, ClonableFn},
10		foldable::Foldable,
11		functor::Functor,
12		lift::Lift,
13		monoid::Monoid,
14		pointed::Pointed,
15		semiapplicative::Semiapplicative,
16		semimonad::Semimonad,
17		traversable::Traversable,
18	},
19	hkt::{Apply1L1T, Kind1L1T},
20};
21
22/// Wraps a value.
23#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
24pub struct Identity<A>(pub A);
25
26impl Kind1L1T for IdentityBrand {
27	type Output<'a, A: 'a> = Identity<A>;
28}
29
30impl Functor for IdentityBrand {
31	/// Maps a function over the value in the identity.
32	///
33	/// # Type Signature
34	///
35	/// `forall a b. Functor Identity => (a -> b, Identity a) -> Identity b`
36	///
37	/// # Parameters
38	///
39	/// * `f`: The function to apply.
40	/// * `fa`: The identity to map over.
41	///
42	/// # Returns
43	///
44	/// A new identity containing the result of applying the function.
45	///
46	/// # Examples
47	///
48	/// ```
49	/// use fp_library::classes::functor::map;
50	/// use fp_library::brands::IdentityBrand;
51	/// use fp_library::types::Identity;
52	///
53	/// assert_eq!(map::<IdentityBrand, _, _, _>(|x: i32| x * 2, Identity(5)), Identity(10));
54	/// ```
55	fn map<'a, A: 'a, B: 'a, F>(
56		f: F,
57		fa: Apply1L1T<'a, Self, A>,
58	) -> Apply1L1T<'a, Self, B>
59	where
60		F: Fn(A) -> B + 'a,
61	{
62		Identity(f(fa.0))
63	}
64}
65
66impl Lift for IdentityBrand {
67	/// Lifts a binary function into the identity context.
68	///
69	/// # Type Signature
70	///
71	/// `forall a b c. Lift Identity => ((a, b) -> c, Identity a, Identity b) -> Identity c`
72	///
73	/// # Parameters
74	///
75	/// * `f`: The binary function to apply.
76	/// * `fa`: The first identity.
77	/// * `fb`: The second identity.
78	///
79	/// # Returns
80	///
81	/// A new identity containing the result of applying the function.
82	///
83	/// # Examples
84	///
85	/// ```
86	/// use fp_library::classes::lift::lift2;
87	/// use fp_library::brands::IdentityBrand;
88	/// use fp_library::types::Identity;
89	///
90	/// assert_eq!(
91	///     lift2::<IdentityBrand, _, _, _, _>(|x: i32, y: i32| x + y, Identity(1), Identity(2)),
92	///     Identity(3)
93	/// );
94	/// ```
95	fn lift2<'a, A, B, C, F>(
96		f: F,
97		fa: Apply1L1T<'a, Self, A>,
98		fb: Apply1L1T<'a, Self, B>,
99	) -> Apply1L1T<'a, Self, C>
100	where
101		F: Fn(A, B) -> C + 'a,
102		A: 'a,
103		B: 'a,
104		C: 'a,
105	{
106		Identity(f(fa.0, fb.0))
107	}
108}
109
110impl Pointed for IdentityBrand {
111	/// Wraps a value in an identity.
112	///
113	/// # Type Signature
114	///
115	/// `forall a. Pointed Identity => a -> Identity a`
116	///
117	/// # Parameters
118	///
119	/// * `a`: The value to wrap.
120	///
121	/// # Returns
122	///
123	/// An identity containing the value.
124	///
125	/// # Examples
126	///
127	/// ```
128	/// use fp_library::classes::pointed::pure;
129	/// use fp_library::brands::IdentityBrand;
130	/// use fp_library::types::Identity;
131	///
132	/// assert_eq!(pure::<IdentityBrand, _>(5), Identity(5));
133	/// ```
134	fn pure<'a, A: 'a>(a: A) -> Apply1L1T<'a, Self, A> {
135		Identity(a)
136	}
137}
138
139impl ApplyFirst for IdentityBrand {}
140impl ApplySecond for IdentityBrand {}
141
142impl Semiapplicative for IdentityBrand {
143	/// Applies a wrapped function to a wrapped value.
144	///
145	/// # Type Signature
146	///
147	/// `forall a b. Semiapplicative Identity => (Identity (a -> b), Identity a) -> Identity b`
148	///
149	/// # Parameters
150	///
151	/// * `ff`: The identity containing the function.
152	/// * `fa`: The identity containing the value.
153	///
154	/// # Returns
155	///
156	/// A new identity containing the result of applying the function.
157	///
158	/// # Examples
159	///
160	/// ```
161	/// use fp_library::classes::semiapplicative::apply;
162	/// use fp_library::classes::clonable_fn::ClonableFn;
163	/// use fp_library::brands::{IdentityBrand};
164	/// use fp_library::types::Identity;
165	/// use fp_library::brands::RcFnBrand;
166	/// use std::rc::Rc;
167	///
168	/// let f = Identity(<RcFnBrand as ClonableFn>::new(|x: i32| x * 2));
169	/// assert_eq!(apply::<IdentityBrand, _, _, RcFnBrand>(f, Identity(5)), Identity(10));
170	/// ```
171	fn apply<'a, A: 'a + Clone, B: 'a, FnBrand: 'a + ClonableFn>(
172		ff: Apply1L1T<'a, Self, ApplyClonableFn<'a, FnBrand, A, B>>,
173		fa: Apply1L1T<'a, Self, A>,
174	) -> Apply1L1T<'a, Self, B> {
175		Identity(ff.0(fa.0))
176	}
177}
178
179impl Semimonad for IdentityBrand {
180	/// Chains identity computations.
181	///
182	/// # Type Signature
183	///
184	/// `forall a b. Semimonad Identity => (Identity a, a -> Identity b) -> Identity b`
185	///
186	/// # Parameters
187	///
188	/// * `ma`: The first identity.
189	/// * `f`: The function to apply to the value inside the identity.
190	///
191	/// # Returns
192	///
193	/// The result of applying `f` to the value.
194	///
195	/// # Examples
196	///
197	/// ```
198	/// use fp_library::classes::semimonad::bind;
199	/// use fp_library::brands::IdentityBrand;
200	/// use fp_library::types::Identity;
201	///
202	/// assert_eq!(
203	///     bind::<IdentityBrand, _, _, _>(Identity(5), |x| Identity(x * 2)),
204	///     Identity(10)
205	/// );
206	/// ```
207	fn bind<'a, A: 'a, B: 'a, F>(
208		ma: Apply1L1T<'a, Self, A>,
209		f: F,
210	) -> Apply1L1T<'a, Self, B>
211	where
212		F: Fn(A) -> Apply1L1T<'a, Self, B> + 'a,
213	{
214		f(ma.0)
215	}
216}
217
218impl Foldable for IdentityBrand {
219	/// Folds the identity from the right.
220	///
221	/// # Type Signature
222	///
223	/// `forall a b. Foldable Identity => ((a, b) -> b, b, Identity a) -> b`
224	///
225	/// # Parameters
226	///
227	/// * `f`: The folding function.
228	/// * `init`: The initial value.
229	/// * `fa`: The identity to fold.
230	///
231	/// # Returns
232	///
233	/// `f(a, init)`.
234	///
235	/// # Examples
236	///
237	/// ```
238	/// use fp_library::classes::foldable::fold_right;
239	/// use fp_library::brands::IdentityBrand;
240	/// use fp_library::types::Identity;
241	///
242	/// assert_eq!(fold_right::<IdentityBrand, _, _, _>(|x: i32, acc| x + acc, 0, Identity(5)), 5);
243	/// ```
244	fn fold_right<'a, A: 'a, B: 'a, F>(
245		f: F,
246		init: B,
247		fa: Apply1L1T<'a, Self, A>,
248	) -> B
249	where
250		F: Fn(A, B) -> B + 'a,
251	{
252		f(fa.0, init)
253	}
254
255	/// Folds the identity from the left.
256	///
257	/// # Type Signature
258	///
259	/// `forall a b. Foldable Identity => ((b, a) -> b, b, Identity a) -> b`
260	///
261	/// # Parameters
262	///
263	/// * `f`: The folding function.
264	/// * `init`: The initial value.
265	/// * `fa`: The identity to fold.
266	///
267	/// # Returns
268	///
269	/// `f(init, a)`.
270	///
271	/// # Examples
272	///
273	/// ```
274	/// use fp_library::classes::foldable::fold_left;
275	/// use fp_library::brands::IdentityBrand;
276	/// use fp_library::types::Identity;
277	///
278	/// assert_eq!(fold_left::<IdentityBrand, _, _, _>(|acc, x: i32| acc + x, 0, Identity(5)), 5);
279	/// ```
280	fn fold_left<'a, A: 'a, B: 'a, F>(
281		f: F,
282		init: B,
283		fa: Apply1L1T<'a, Self, A>,
284	) -> B
285	where
286		F: Fn(B, A) -> B + 'a,
287	{
288		f(init, fa.0)
289	}
290
291	/// Maps the value to a monoid and returns it.
292	///
293	/// # Type Signature
294	///
295	/// `forall a m. (Foldable Identity, Monoid m) => ((a) -> m, Identity a) -> m`
296	///
297	/// # Parameters
298	///
299	/// * `f`: The mapping function.
300	/// * `fa`: The identity to fold.
301	///
302	/// # Returns
303	///
304	/// `f(a)`.
305	///
306	/// # Examples
307	///
308	/// ```
309	/// use fp_library::classes::foldable::fold_map;
310	/// use fp_library::brands::IdentityBrand;
311	/// use fp_library::types::Identity;
312	/// use fp_library::types::string; // Import to bring Monoid impl for String into scope
313	///
314	/// assert_eq!(fold_map::<IdentityBrand, _, _, _>(|x: i32| x.to_string(), Identity(5)), "5".to_string());
315	/// ```
316	fn fold_map<'a, A: 'a, M, F>(
317		f: F,
318		fa: Apply1L1T<'a, Self, A>,
319	) -> M
320	where
321		M: Monoid + 'a,
322		F: Fn(A) -> M + 'a,
323	{
324		f(fa.0)
325	}
326}
327
328impl Traversable for IdentityBrand {
329	/// Traverses the identity with an applicative function.
330	///
331	/// # Type Signature
332	///
333	/// `forall a b f. (Traversable Identity, Applicative f) => (a -> f b, Identity a) -> f (Identity b)`
334	///
335	/// # Parameters
336	///
337	/// * `f`: The function to apply.
338	/// * `ta`: The identity to traverse.
339	///
340	/// # Returns
341	///
342	/// The identity wrapped in the applicative context.
343	///
344	/// # Examples
345	///
346	/// ```
347	/// use fp_library::classes::traversable::traverse;
348	/// use fp_library::brands::{IdentityBrand, OptionBrand};
349	/// use fp_library::types::Identity;
350	///
351	/// assert_eq!(
352	///     traverse::<IdentityBrand, OptionBrand, _, _, _>(|x| Some(x * 2), Identity(5)),
353	///     Some(Identity(10))
354	/// );
355	/// ```
356	fn traverse<'a, F: Applicative, A: 'a + Clone, B: 'a + Clone, Func>(
357		f: Func,
358		ta: Apply1L1T<'a, Self, A>,
359	) -> Apply1L1T<'a, F, Apply1L1T<'a, Self, B>>
360	where
361		Func: Fn(A) -> Apply1L1T<'a, F, B> + 'a,
362		Apply1L1T<'a, Self, B>: Clone,
363	{
364		F::map(|b| Identity(b), f(ta.0))
365	}
366
367	/// Sequences an identity of applicative.
368	///
369	/// # Type Signature
370	///
371	/// `forall a f. (Traversable Identity, Applicative f) => (Identity (f a)) -> f (Identity a)`
372	///
373	/// # Parameters
374	///
375	/// * `ta`: The identity containing the applicative value.
376	///
377	/// # Returns
378	///
379	/// The identity wrapped in the applicative context.
380	///
381	/// # Examples
382	///
383	/// ```
384	/// use fp_library::classes::traversable::sequence;
385	/// use fp_library::brands::{IdentityBrand, OptionBrand};
386	/// use fp_library::types::Identity;
387	///
388	/// assert_eq!(
389	///     sequence::<IdentityBrand, OptionBrand, _>(Identity(Some(5))),
390	///     Some(Identity(5))
391	/// );
392	/// ```
393	fn sequence<'a, F: Applicative, A: 'a + Clone>(
394		ta: Apply1L1T<'a, Self, Apply1L1T<'a, F, A>>
395	) -> Apply1L1T<'a, F, Apply1L1T<'a, Self, A>>
396	where
397		Apply1L1T<'a, F, A>: Clone,
398		Apply1L1T<'a, Self, A>: Clone,
399	{
400		F::map(|a| Identity(a), ta.0)
401	}
402}
403
404#[cfg(test)]
405mod tests {
406	use super::*;
407	use crate::{
408		brands::{OptionBrand, RcFnBrand},
409		classes::{functor::map, pointed::pure, semiapplicative::apply, semimonad::bind},
410		functions::{compose, identity},
411	};
412	use quickcheck_macros::quickcheck;
413
414	// Functor Laws
415
416	/// Tests the identity law for Functor.
417	#[quickcheck]
418	fn functor_identity(x: i32) -> bool {
419		let x = Identity(x);
420		map::<IdentityBrand, _, _, _>(identity, x) == x
421	}
422
423	/// Tests the composition law for Functor.
424	#[quickcheck]
425	fn functor_composition(x: i32) -> bool {
426		let x = Identity(x);
427		let f = |x: i32| x.wrapping_add(1);
428		let g = |x: i32| x.wrapping_mul(2);
429		map::<IdentityBrand, _, _, _>(compose(f, g), x)
430			== map::<IdentityBrand, _, _, _>(f, map::<IdentityBrand, _, _, _>(g, x))
431	}
432
433	// Applicative Laws
434
435	/// Tests the identity law for Applicative.
436	#[quickcheck]
437	fn applicative_identity(v: i32) -> bool {
438		let v = Identity(v);
439		apply::<IdentityBrand, _, _, RcFnBrand>(
440			pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(identity)),
441			v,
442		) == v
443	}
444
445	/// Tests the homomorphism law for Applicative.
446	#[quickcheck]
447	fn applicative_homomorphism(x: i32) -> bool {
448		let f = |x: i32| x.wrapping_mul(2);
449		apply::<IdentityBrand, _, _, RcFnBrand>(
450			pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(f)),
451			pure::<IdentityBrand, _>(x),
452		) == pure::<IdentityBrand, _>(f(x))
453	}
454
455	/// Tests the composition law for Applicative.
456	#[quickcheck]
457	fn applicative_composition(
458		w: i32,
459		u_val: i32,
460		v_val: i32,
461	) -> bool {
462		let w = Identity(w);
463		let v_fn = move |x: i32| x.wrapping_mul(v_val);
464		let u_fn = move |x: i32| x.wrapping_add(u_val);
465
466		let v = pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(v_fn));
467		let u = pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(u_fn));
468
469		// RHS: u <*> (v <*> w)
470		let vw = apply::<IdentityBrand, _, _, RcFnBrand>(v.clone(), w.clone());
471		let rhs = apply::<IdentityBrand, _, _, RcFnBrand>(u.clone(), vw);
472
473		// LHS: pure(compose) <*> u <*> v <*> w
474		// equivalent to (u . v) <*> w
475		let composed = move |x| u_fn(v_fn(x));
476		let uv = pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(composed));
477
478		let lhs = apply::<IdentityBrand, _, _, RcFnBrand>(uv, w);
479
480		lhs == rhs
481	}
482
483	/// Tests the interchange law for Applicative.
484	#[quickcheck]
485	fn applicative_interchange(y: i32) -> bool {
486		// u <*> pure y = pure ($ y) <*> u
487		let f = |x: i32| x.wrapping_mul(2);
488		let u = pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(f));
489
490		let lhs = apply::<IdentityBrand, _, _, RcFnBrand>(u.clone(), pure::<IdentityBrand, _>(y));
491
492		let rhs_fn = <RcFnBrand as ClonableFn>::new(move |f: std::rc::Rc<dyn Fn(i32) -> i32>| f(y));
493		let rhs = apply::<IdentityBrand, _, _, RcFnBrand>(pure::<IdentityBrand, _>(rhs_fn), u);
494
495		lhs == rhs
496	}
497
498	// Monad Laws
499
500	/// Tests the left identity law for Monad.
501	#[quickcheck]
502	fn monad_left_identity(a: i32) -> bool {
503		let f = |x: i32| Identity(x.wrapping_mul(2));
504		bind::<IdentityBrand, _, _, _>(pure::<IdentityBrand, _>(a), f) == f(a)
505	}
506
507	/// Tests the right identity law for Monad.
508	#[quickcheck]
509	fn monad_right_identity(m: i32) -> bool {
510		let m = Identity(m);
511		bind::<IdentityBrand, _, _, _>(m, pure::<IdentityBrand, _>) == m
512	}
513
514	/// Tests the associativity law for Monad.
515	#[quickcheck]
516	fn monad_associativity(m: i32) -> bool {
517		let m = Identity(m);
518		let f = |x: i32| Identity(x.wrapping_mul(2));
519		let g = |x: i32| Identity(x.wrapping_add(1));
520		bind::<IdentityBrand, _, _, _>(bind::<IdentityBrand, _, _, _>(m, f), g)
521			== bind::<IdentityBrand, _, _, _>(m, |x| bind::<IdentityBrand, _, _, _>(f(x), g))
522	}
523
524	// Edge Cases
525
526	/// Tests the `map` function.
527	#[test]
528	fn map_test() {
529		assert_eq!(map::<IdentityBrand, _, _, _>(|x: i32| x + 1, Identity(1)), Identity(2));
530	}
531
532	/// Tests the `bind` function.
533	#[test]
534	fn bind_test() {
535		assert_eq!(bind::<IdentityBrand, _, _, _>(Identity(1), |x| Identity(x + 1)), Identity(2));
536	}
537
538	/// Tests the `fold_right` function.
539	#[test]
540	fn fold_right_test() {
541		assert_eq!(
542			crate::classes::foldable::fold_right::<IdentityBrand, _, _, _>(
543				|x: i32, acc| x + acc,
544				0,
545				Identity(1)
546			),
547			1
548		);
549	}
550
551	/// Tests the `fold_left` function.
552	#[test]
553	fn fold_left_test() {
554		assert_eq!(
555			crate::classes::foldable::fold_left::<IdentityBrand, _, _, _>(
556				|acc, x: i32| acc + x,
557				0,
558				Identity(1)
559			),
560			1
561		);
562	}
563
564	/// Tests the `traverse` function.
565	#[test]
566	fn traverse_test() {
567		assert_eq!(
568			crate::classes::traversable::traverse::<IdentityBrand, OptionBrand, _, _, _>(
569				|x: i32| Some(x + 1),
570				Identity(1)
571			),
572			Some(Identity(2))
573		);
574	}
575}