fp_library/types/
pair.rs

1//! Implementations for [`Pair`], a type that wraps two values.
2
3use crate::{
4	Apply,
5	brands::{PairBrand, PairWithFirstBrand, PairWithSecondBrand},
6	classes::{
7		applicative::Applicative, apply_first::ApplyFirst, apply_second::ApplySecond,
8		clonable_fn::ClonableFn, foldable::Foldable, functor::Functor, lift::Lift, monoid::Monoid,
9		pointed::Pointed, semiapplicative::Semiapplicative, semigroup::Semigroup,
10		semimonad::Semimonad, traversable::Traversable,
11	},
12	impl_kind,
13	kinds::*,
14};
15
16/// Wraps two values.
17#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
18pub struct Pair<First, Second>(pub First, pub Second);
19
20impl_kind! {
21	for PairBrand {
22		type Of<A, B> = Pair<A, B>;
23	}
24}
25
26// PairWithFirstBrand<First> (Functor over Second)
27
28impl_kind! {
29	impl<First: 'static> for PairWithFirstBrand<First> {
30		type Of<'a, A: 'a>: 'a = Pair<First, A>;
31	}
32}
33
34impl<First: 'static> Functor for PairWithFirstBrand<First> {
35	/// Maps a function over the second value in the pair.
36	///
37	/// # Type Signature
38	///
39	/// `forall a b t. Functor (Pair t) => (a -> b, Pair t a) -> Pair t b`
40	///
41	/// # Parameters
42	///
43	/// * `f`: The function to apply to the second value.
44	/// * `fa`: The pair to map over.
45	///
46	/// # Returns
47	///
48	/// A new pair containing the result of applying the function to the second value.
49	///
50	/// # Examples
51	///
52	/// ```
53	/// use fp_library::classes::functor::map;
54	/// use fp_library::brands::PairWithFirstBrand;
55	/// use fp_library::types::Pair;
56	///
57	/// assert_eq!(map::<PairWithFirstBrand<_>, _, _, _>(|x: i32| x * 2, Pair(1, 5)), Pair(1, 10));
58	/// ```
59	fn map<'a, A: 'a, B: 'a, F>(
60		f: F,
61		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
62	) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a)
63	where
64		F: Fn(A) -> B + 'a,
65	{
66		Pair(fa.0, f(fa.1))
67	}
68}
69
70impl<First: Clone + 'static> Lift for PairWithFirstBrand<First>
71where
72	First: Semigroup,
73{
74	/// Lifts a binary function into the pair context (over second).
75	///
76	/// # Type Signature
77	///
78	/// `forall a b c t. (Lift (Pair t), Semigroup t) => ((a, b) -> c, Pair t a, Pair t b) -> Pair t c`
79	///
80	/// # Parameters
81	///
82	/// * `f`: The binary function to apply to the second values.
83	/// * `fa`: The first pair.
84	/// * `fb`: The second pair.
85	///
86	/// # Returns
87	///
88	/// A new pair where the first values are combined using `Semigroup::append` and the second values are combined using `f`.
89	///
90	/// # Examples
91	///
92	/// ```
93	/// use fp_library::classes::lift::lift2;
94	/// use fp_library::brands::PairWithFirstBrand;
95	/// use fp_library::types::Pair;
96	/// use fp_library::types::string;
97	///
98	/// assert_eq!(
99	///     lift2::<PairWithFirstBrand<String>, _, _, _, _>(|x, y| x + y, Pair("a".to_string(), 1), Pair("b".to_string(), 2)),
100	///     Pair("ab".to_string(), 3)
101	/// );
102	/// ```
103	fn lift2<'a, A, B, C, F>(
104		f: F,
105		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
106		fb: Apply!(brand: Self, signature: ('a, B: 'a) -> 'a),
107	) -> Apply!(brand: Self, signature: ('a, C: 'a) -> 'a)
108	where
109		F: Fn(A, B) -> C + 'a,
110		A: Clone + 'a,
111		B: Clone + 'a,
112		C: 'a,
113	{
114		Pair(Semigroup::append(fa.0, fb.0), f(fa.1, fb.1))
115	}
116}
117
118impl<First: Clone + 'static> Pointed for PairWithFirstBrand<First>
119where
120	First: Monoid,
121{
122	/// Wraps a value in a pair (with empty first).
123	///
124	/// # Type Signature
125	///
126	/// `forall a t. (Pointed (Pair t), Monoid t) => a -> Pair t a`
127	///
128	/// # Parameters
129	///
130	/// * `a`: The value to wrap.
131	///
132	/// # Returns
133	///
134	/// A pair containing the empty value of the first type and `a`.
135	///
136	/// # Examples
137	///
138	/// ```
139	/// use fp_library::classes::pointed::pure;
140	/// use fp_library::brands::PairWithFirstBrand;
141	/// use fp_library::types::Pair;
142	/// use fp_library::types::string;
143	///
144	/// assert_eq!(pure::<PairWithFirstBrand<String>, _>(5), Pair("".to_string(), 5));
145	/// ```
146	fn pure<'a, A: 'a>(a: A) -> Apply!(brand: Self, signature: ('a, A: 'a) -> 'a) {
147		Pair(Monoid::empty(), a)
148	}
149}
150
151impl<First: Clone + Semigroup + 'static> ApplyFirst for PairWithFirstBrand<First> {}
152impl<First: Clone + Semigroup + 'static> ApplySecond for PairWithFirstBrand<First> {}
153
154impl<First: Clone + 'static> Semiapplicative for PairWithFirstBrand<First>
155where
156	First: Semigroup,
157{
158	/// Applies a wrapped function to a wrapped value (over second).
159	///
160	/// # Type Signature
161	///
162	/// `forall a b t. (Semiapplicative (Pair t), Semigroup t) => (Pair t (a -> b), Pair t a) -> Pair t b`
163	///
164	/// # Parameters
165	///
166	/// * `ff`: The pair containing the function.
167	/// * `fa`: The pair containing the value.
168	///
169	/// # Returns
170	///
171	/// A new pair where the first values are combined and the function is applied to the second value.
172	///
173	/// # Examples
174	///
175	/// ```
176	/// use fp_library::classes::semiapplicative::apply;
177	/// use fp_library::classes::clonable_fn::ClonableFn;
178	/// use fp_library::brands::PairWithFirstBrand;
179	/// use fp_library::types::Pair;
180	/// use fp_library::brands::RcFnBrand;
181	/// use fp_library::types::string;
182	/// use std::rc::Rc;
183	///
184	/// let f = Pair("a".to_string(), <RcFnBrand as ClonableFn>::new(|x: i32| x * 2));
185	/// assert_eq!(apply::<PairWithFirstBrand<String>, _, _, RcFnBrand>(f, Pair("b".to_string(), 5)), Pair("ab".to_string(), 10));
186	/// ```
187	fn apply<'a, A: 'a + Clone, B: 'a, FnBrand: 'a + ClonableFn>(
188		ff: Apply!(brand: Self, signature: ('a, Apply!(brand: FnBrand, kind: ClonableFn, lifetimes: ('a), types: (A, B)): 'a) -> 'a),
189		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
190	) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a) {
191		Pair(Semigroup::append(ff.0, fa.0), ff.1(fa.1))
192	}
193}
194
195impl<First: Clone + 'static> Semimonad for PairWithFirstBrand<First>
196where
197	First: Semigroup,
198{
199	/// Chains pair computations (over second).
200	///
201	/// # Type Signature
202	///
203	/// `forall a b t. (Semimonad (Pair t), Semigroup t) => (Pair t a, a -> Pair t b) -> Pair t b`
204	///
205	/// # Parameters
206	///
207	/// * `ma`: The first pair.
208	/// * `f`: The function to apply to the second value.
209	///
210	/// # Returns
211	///
212	/// A new pair where the first values are combined.
213	///
214	/// # Examples
215	///
216	/// ```
217	/// use fp_library::classes::semimonad::bind;
218	/// use fp_library::brands::PairWithFirstBrand;
219	/// use fp_library::types::Pair;
220	/// use fp_library::types::string;
221	///
222	/// assert_eq!(
223	///     bind::<PairWithFirstBrand<String>, _, _, _>(Pair("a".to_string(), 5), |x| Pair("b".to_string(), x * 2)),
224	///     Pair("ab".to_string(), 10)
225	/// );
226	/// ```
227	fn bind<'a, A: 'a, B: 'a, F>(
228		ma: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
229		f: F,
230	) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a)
231	where
232		F: Fn(A) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a) + 'a,
233	{
234		let Pair(first, second) = ma;
235		let Pair(next_first, next_second) = f(second);
236		Pair(Semigroup::append(first, next_first), next_second)
237	}
238}
239
240impl<First: 'static> Foldable for PairWithFirstBrand<First> {
241	/// Folds the pair from the right (over second).
242	///
243	/// # Type Signature
244	///
245	/// `forall a b t. Foldable (Pair t) => ((a, b) -> b, b, Pair t a) -> b`
246	///
247	/// # Parameters
248	///
249	/// * `f`: The folding function.
250	/// * `init`: The initial value.
251	/// * `fa`: The pair to fold.
252	///
253	/// # Returns
254	///
255	/// `f(a, init)`.
256	///
257	/// # Examples
258	///
259	/// ```
260	/// use fp_library::classes::foldable::fold_right;
261	/// use fp_library::brands::PairWithFirstBrand;
262	/// use fp_library::types::Pair;
263	///
264	/// assert_eq!(fold_right::<PairWithFirstBrand<()>, _, _, _>(|x, acc| x + acc, 0, Pair((), 5)), 5);
265	/// ```
266	fn fold_right<'a, A: 'a, B: 'a, F>(
267		f: F,
268		init: B,
269		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
270	) -> B
271	where
272		F: Fn(A, B) -> B + 'a,
273	{
274		f(fa.1, init)
275	}
276
277	/// Folds the pair from the left (over second).
278	///
279	/// # Type Signature
280	///
281	/// `forall a b t. Foldable (Pair t) => ((b, a) -> b, b, Pair t a) -> b`
282	///
283	/// # Parameters
284	///
285	/// * `f`: The folding function.
286	/// * `init`: The initial value.
287	/// * `fa`: The pair to fold.
288	///
289	/// # Returns
290	///
291	/// `f(init, a)`.
292	///
293	/// # Examples
294	///
295	/// ```
296	/// use fp_library::classes::foldable::fold_left;
297	/// use fp_library::brands::PairWithFirstBrand;
298	/// use fp_library::types::Pair;
299	///
300	/// assert_eq!(fold_left::<PairWithFirstBrand<()>, _, _, _>(|acc, x| acc + x, 0, Pair((), 5)), 5);
301	/// ```
302	fn fold_left<'a, A: 'a, B: 'a, F>(
303		f: F,
304		init: B,
305		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
306	) -> B
307	where
308		F: Fn(B, A) -> B + 'a,
309	{
310		f(init, fa.1)
311	}
312
313	/// Maps the value to a monoid and returns it (over second).
314	///
315	/// # Type Signature
316	///
317	/// `forall a m t. (Foldable (Pair t), Monoid m) => ((a) -> m, Pair t a) -> m`
318	///
319	/// # Parameters
320	///
321	/// * `f`: The mapping function.
322	/// * `fa`: The pair to fold.
323	///
324	/// # Returns
325	///
326	/// `f(a)`.
327	///
328	/// # Examples
329	///
330	/// ```
331	/// use fp_library::classes::foldable::fold_map;
332	/// use fp_library::brands::PairWithFirstBrand;
333	/// use fp_library::types::Pair;
334	/// use fp_library::types::string;
335	///
336	/// assert_eq!(
337	///     fold_map::<PairWithFirstBrand<()>, _, _, _>(|x: i32| x.to_string(), Pair((), 5)),
338	///     "5".to_string()
339	/// );
340	/// ```
341	fn fold_map<'a, A: 'a, M, F>(
342		f: F,
343		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
344	) -> M
345	where
346		M: Monoid + 'a,
347		F: Fn(A) -> M + 'a,
348	{
349		f(fa.1)
350	}
351}
352
353impl<First: Clone + 'static> Traversable for PairWithFirstBrand<First> {
354	/// Traverses the pair with an applicative function (over second).
355	///
356	/// # Type Signature
357	///
358	/// `forall a b f t. (Traversable (Pair t), Applicative f) => (a -> f b, Pair t a) -> f (Pair t b)`
359	///
360	/// # Parameters
361	///
362	/// * `f`: The function to apply.
363	/// * `ta`: The pair to traverse.
364	///
365	/// # Returns
366	///
367	/// The pair wrapped in the applicative context.
368	///
369	/// # Examples
370	///
371	/// ```
372	/// use fp_library::classes::traversable::traverse;
373	/// use fp_library::brands::{PairWithFirstBrand, OptionBrand};
374	/// use fp_library::types::Pair;
375	///
376	/// assert_eq!(
377	///     traverse::<PairWithFirstBrand<()>, OptionBrand, _, _, _>(|x| Some(x * 2), Pair((), 5)),
378	///     Some(Pair((), 10))
379	/// );
380	/// ```
381	fn traverse<'a, F: Applicative, A: 'a + Clone, B: 'a + Clone, Func>(
382		f: Func,
383		ta: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
384	) -> Apply!(brand: F, signature: ('a, Apply!(brand: Self, signature: ('a, B: 'a) -> 'a): 'a) -> 'a)
385	where
386		Func: Fn(A) -> Apply!(brand: F, signature: ('a, B: 'a) -> 'a) + 'a,
387		Apply!(brand: Self, signature: ('a, B: 'a) -> 'a): Clone,
388	{
389		let Pair(first, second) = ta;
390		F::map(move |b| Pair(first.clone(), b), f(second))
391	}
392
393	/// Sequences a pair of applicative (over second).
394	///
395	/// # Type Signature
396	///
397	/// `forall a f t. (Traversable (Pair t), Applicative f) => (Pair t (f a)) -> f (Pair t a)`
398	///
399	/// # Parameters
400	///
401	/// * `ta`: The pair containing the applicative value.
402	///
403	/// # Returns
404	///
405	/// The pair wrapped in the applicative context.
406	///
407	/// # Examples
408	///
409	/// ```
410	/// use fp_library::classes::traversable::sequence;
411	/// use fp_library::brands::{PairWithFirstBrand, OptionBrand};
412	/// use fp_library::types::Pair;
413	///
414	/// assert_eq!(
415	///     sequence::<PairWithFirstBrand<()>, OptionBrand, _>(Pair((), Some(5))),
416	///     Some(Pair((), 5))
417	/// );
418	/// ```
419	fn sequence<'a, F: Applicative, A: 'a + Clone>(
420		ta: Apply!(brand: Self, signature: ('a, Apply!(brand: F, signature: ('a, A: 'a) -> 'a): 'a) -> 'a)
421	) -> Apply!(brand: F, signature: ('a, Apply!(brand: Self, signature: ('a, A: 'a) -> 'a): 'a) -> 'a)
422	where
423		Apply!(brand: F, signature: ('a, A: 'a) -> 'a): Clone,
424		Apply!(brand: Self, signature: ('a, A: 'a) -> 'a): Clone,
425	{
426		let Pair(first, second) = ta;
427		F::map(move |a| Pair(first.clone(), a), second)
428	}
429}
430
431// PairWithSecondBrand<Second> (Functor over First)
432
433impl_kind! {
434	impl<Second: 'static> for PairWithSecondBrand<Second> {
435		type Of<'a, A: 'a>: 'a = Pair<A, Second>;
436	}
437}
438
439impl<Second: 'static> Functor for PairWithSecondBrand<Second> {
440	/// Maps a function over the first value in the pair.
441	///
442	/// # Type Signature
443	///
444	/// `forall a b t. Functor (Pair' t) => (a -> b, Pair a t) -> Pair b t`
445	///
446	/// # Parameters
447	///
448	/// * `f`: The function to apply to the first value.
449	/// * `fa`: The pair to map over.
450	///
451	/// # Returns
452	///
453	/// A new pair containing the result of applying the function to the first value.
454	///
455	/// # Examples
456	///
457	/// ```
458	/// use fp_library::classes::functor::map;
459	/// use fp_library::brands::PairWithSecondBrand;
460	/// use fp_library::types::Pair;
461	///
462	/// assert_eq!(map::<PairWithSecondBrand<_>, _, _, _>(|x: i32| x * 2, Pair(5, 1)), Pair(10, 1));
463	/// ```
464	fn map<'a, A: 'a, B: 'a, F>(
465		f: F,
466		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
467	) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a)
468	where
469		F: Fn(A) -> B + 'a,
470	{
471		Pair(f(fa.0), fa.1)
472	}
473}
474
475impl<Second: Clone + 'static> Lift for PairWithSecondBrand<Second>
476where
477	Second: Semigroup,
478{
479	/// Lifts a binary function into the pair context (over first).
480	///
481	/// # Type Signature
482	///
483	/// `forall a b c t. (Lift (Pair' t), Semigroup t) => ((a, b) -> c, Pair a t, Pair b t) -> Pair c t`
484	///
485	/// # Parameters
486	///
487	/// * `f`: The binary function to apply to the first values.
488	/// * `fa`: The first pair.
489	/// * `fb`: The second pair.
490	///
491	/// # Returns
492	///
493	/// A new pair where the first values are combined using `f` and the second values are combined using `Semigroup::append`.
494	///
495	/// # Examples
496	///
497	/// ```
498	/// use fp_library::classes::lift::lift2;
499	/// use fp_library::brands::PairWithSecondBrand;
500	/// use fp_library::types::Pair;
501	/// use fp_library::types::string;
502	///
503	/// assert_eq!(
504	///     lift2::<PairWithSecondBrand<String>, _, _, _, _>(|x, y| x + y, Pair(1, "a".to_string()), Pair(2, "b".to_string())),
505	///     Pair(3, "ab".to_string())
506	/// );
507	/// ```
508	fn lift2<'a, A, B, C, F>(
509		f: F,
510		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
511		fb: Apply!(brand: Self, signature: ('a, B: 'a) -> 'a),
512	) -> Apply!(brand: Self, signature: ('a, C: 'a) -> 'a)
513	where
514		F: Fn(A, B) -> C + 'a,
515		A: Clone + 'a,
516		B: Clone + 'a,
517		C: 'a,
518	{
519		Pair(f(fa.0, fb.0), Semigroup::append(fa.1, fb.1))
520	}
521}
522
523impl<Second: Clone + 'static> Pointed for PairWithSecondBrand<Second>
524where
525	Second: Monoid,
526{
527	/// Wraps a value in a pair (with empty second).
528	///
529	/// # Type Signature
530	///
531	/// `forall a t. (Pointed (Pair' t), Monoid t) => a -> Pair a t`
532	///
533	/// # Parameters
534	///
535	/// * `a`: The value to wrap.
536	///
537	/// # Returns
538	///
539	/// A pair containing `a` and the empty value of the second type.
540	///
541	/// # Examples
542	///
543	/// ```
544	/// use fp_library::classes::pointed::pure;
545	/// use fp_library::brands::PairWithSecondBrand;
546	/// use fp_library::types::Pair;
547	/// use fp_library::types::string;
548	///
549	/// assert_eq!(pure::<PairWithSecondBrand<String>, _>(5), Pair(5, "".to_string()));
550	/// ```
551	fn pure<'a, A: 'a>(a: A) -> Apply!(brand: Self, signature: ('a, A: 'a) -> 'a) {
552		Pair(a, Monoid::empty())
553	}
554}
555
556impl<Second: Clone + Semigroup + 'static> ApplyFirst for PairWithSecondBrand<Second> {}
557impl<Second: Clone + Semigroup + 'static> ApplySecond for PairWithSecondBrand<Second> {}
558
559impl<Second: Clone + 'static> Semiapplicative for PairWithSecondBrand<Second>
560where
561	Second: Semigroup,
562{
563	/// Applies a wrapped function to a wrapped value (over first).
564	///
565	/// # Type Signature
566	///
567	/// `forall a b t. (Semiapplicative (Pair' t), Semigroup t) => (Pair (a -> b) t, Pair a t) -> Pair b t`
568	///
569	/// # Parameters
570	///
571	/// * `ff`: The pair containing the function.
572	/// * `fa`: The pair containing the value.
573	///
574	/// # Returns
575	///
576	/// A new pair where the function is applied to the first value and the second values are combined.
577	///
578	/// # Examples
579	///
580	/// ```
581	/// use fp_library::classes::semiapplicative::apply;
582	/// use fp_library::classes::clonable_fn::ClonableFn;
583	/// use fp_library::brands::PairWithSecondBrand;
584	/// use fp_library::types::Pair;
585	/// use fp_library::brands::RcFnBrand;
586	/// use fp_library::types::string;
587	/// use std::rc::Rc;
588	///
589	/// let f = Pair(<RcFnBrand as ClonableFn>::new(|x: i32| x * 2), "a".to_string());
590	/// assert_eq!(apply::<PairWithSecondBrand<String>, _, _, RcFnBrand>(f, Pair(5, "b".to_string())), Pair(10, "ab".to_string()));
591	/// ```
592	fn apply<'a, A: 'a + Clone, B: 'a, FnBrand: 'a + ClonableFn>(
593		ff: Apply!(brand: Self, signature: ('a, Apply!(brand: FnBrand, kind: ClonableFn, lifetimes: ('a), types: (A, B)): 'a) -> 'a),
594		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
595	) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a) {
596		Pair(ff.0(fa.0), Semigroup::append(ff.1, fa.1))
597	}
598}
599
600impl<Second: Clone + 'static> Semimonad for PairWithSecondBrand<Second>
601where
602	Second: Semigroup,
603{
604	/// Chains pair computations (over first).
605	///
606	/// # Type Signature
607	///
608	/// `forall a b t. (Semimonad (Pair' t), Semigroup t) => (Pair a t, a -> Pair b t) -> Pair b t`
609	///
610	/// # Parameters
611	///
612	/// * `ma`: The first pair.
613	/// * `f`: The function to apply to the first value.
614	///
615	/// # Returns
616	///
617	/// A new pair where the second values are combined.
618	///
619	/// # Examples
620	///
621	/// ```
622	/// use fp_library::classes::semimonad::bind;
623	/// use fp_library::brands::PairWithSecondBrand;
624	/// use fp_library::types::Pair;
625	/// use fp_library::types::string;
626	///
627	/// assert_eq!(
628	///     bind::<PairWithSecondBrand<String>, _, _, _>(Pair(5, "a".to_string()), |x| Pair(x * 2, "b".to_string())),
629	///     Pair(10, "ab".to_string())
630	/// );
631	/// ```
632	fn bind<'a, A: 'a, B: 'a, F>(
633		ma: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
634		f: F,
635	) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a)
636	where
637		F: Fn(A) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a) + 'a,
638	{
639		let Pair(first, second) = ma;
640		let Pair(next_first, next_second) = f(first);
641		Pair(next_first, Semigroup::append(second, next_second))
642	}
643}
644
645impl<Second: 'static> Foldable for PairWithSecondBrand<Second> {
646	/// Folds the pair from the right (over first).
647	///
648	/// # Type Signature
649	///
650	/// `forall a b t. Foldable (Pair' t) => ((a, b) -> b, b, Pair a t) -> b`
651	///
652	/// # Parameters
653	///
654	/// * `f`: The folding function.
655	/// * `init`: The initial value.
656	/// * `fa`: The pair to fold.
657	///
658	/// # Returns
659	///
660	/// `f(a, init)`.
661	///
662	/// # Examples
663	///
664	/// ```
665	/// use fp_library::classes::foldable::fold_right;
666	/// use fp_library::brands::PairWithSecondBrand;
667	/// use fp_library::types::Pair;
668	///
669	/// assert_eq!(fold_right::<PairWithSecondBrand<()>, _, _, _>(|x, acc| x + acc, 0, Pair(5, ())), 5);
670	/// ```
671	fn fold_right<'a, A: 'a, B: 'a, F>(
672		f: F,
673		init: B,
674		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
675	) -> B
676	where
677		F: Fn(A, B) -> B + 'a,
678	{
679		f(fa.0, init)
680	}
681
682	/// Folds the pair from the left (over first).
683	///
684	/// # Type Signature
685	///
686	/// `forall a b t. Foldable (Pair' t) => ((b, a) -> b, b, Pair a t) -> b`
687	///
688	/// # Parameters
689	///
690	/// * `f`: The folding function.
691	/// * `init`: The initial value.
692	/// * `fa`: The pair to fold.
693	///
694	/// # Returns
695	///
696	/// `f(init, a)`.
697	///
698	/// # Examples
699	///
700	/// ```
701	/// use fp_library::classes::foldable::fold_left;
702	/// use fp_library::brands::PairWithSecondBrand;
703	/// use fp_library::types::Pair;
704	///
705	/// assert_eq!(fold_left::<PairWithSecondBrand<()>, _, _, _>(|acc, x| acc + x, 0, Pair(5, ())), 5);
706	/// ```
707	fn fold_left<'a, A: 'a, B: 'a, F>(
708		f: F,
709		init: B,
710		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
711	) -> B
712	where
713		F: Fn(B, A) -> B + 'a,
714	{
715		f(init, fa.0)
716	}
717
718	/// Maps the value to a monoid and returns it (over first).
719	///
720	/// # Type Signature
721	///
722	/// `forall a m t. (Foldable (Pair' t), Monoid m) => ((a) -> m, Pair a t) -> m`
723	///
724	/// # Parameters
725	///
726	/// * `f`: The mapping function.
727	/// * `fa`: The pair to fold.
728	///
729	/// # Returns
730	///
731	/// `f(a)`.
732	///
733	/// # Examples
734	///
735	/// ```
736	/// use fp_library::classes::foldable::fold_map;
737	/// use fp_library::brands::PairWithSecondBrand;
738	/// use fp_library::types::Pair;
739	/// use fp_library::types::string;
740	///
741	/// assert_eq!(
742	///     fold_map::<PairWithSecondBrand<()>, _, _, _>(|x: i32| x.to_string(), Pair(5, ())),
743	///     "5".to_string()
744	/// );
745	/// ```
746	fn fold_map<'a, A: 'a, M, F>(
747		f: F,
748		fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
749	) -> M
750	where
751		M: Monoid + 'a,
752		F: Fn(A) -> M + 'a,
753	{
754		f(fa.0)
755	}
756}
757
758impl<Second: Clone + 'static> Traversable for PairWithSecondBrand<Second> {
759	/// Traverses the pair with an applicative function (over first).
760	///
761	/// # Type Signature
762	///
763	/// `forall a b f t. (Traversable (Pair' t), Applicative f) => (a -> f b, Pair a t) -> f (Pair b t)`
764	///
765	/// # Parameters
766	///
767	/// * `f`: The function to apply.
768	/// * `ta`: The pair to traverse.
769	///
770	/// # Returns
771	///
772	/// The pair wrapped in the applicative context.
773	///
774	/// # Examples
775	///
776	/// ```
777	/// use fp_library::classes::traversable::traverse;
778	/// use fp_library::brands::{PairWithSecondBrand, OptionBrand};
779	/// use fp_library::types::Pair;
780	///
781	/// assert_eq!(
782	///     traverse::<PairWithSecondBrand<()>, OptionBrand, _, _, _>(|x| Some(x * 2), Pair(5, ())),
783	///     Some(Pair(10, ()))
784	/// );
785	/// ```
786	fn traverse<'a, F: Applicative, A: 'a + Clone, B: 'a + Clone, Func>(
787		f: Func,
788		ta: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
789	) -> Apply!(brand: F, signature: ('a, Apply!(brand: Self, signature: ('a, B: 'a) -> 'a): 'a) -> 'a)
790	where
791		Func: Fn(A) -> Apply!(brand: F, signature: ('a, B: 'a) -> 'a) + 'a,
792		Apply!(brand: Self, signature: ('a, B: 'a) -> 'a): Clone,
793	{
794		let Pair(first, second) = ta;
795		F::map(move |b| Pair(b, second.clone()), f(first))
796	}
797
798	/// Sequences a pair of applicative (over first).
799	///
800	/// # Type Signature
801	///
802	/// `forall a f t. (Traversable (Pair' t), Applicative f) => (Pair (f a) t) -> f (Pair a t)`
803	///
804	/// # Parameters
805	///
806	/// * `ta`: The pair containing the applicative value.
807	///
808	/// # Returns
809	///
810	/// The pair wrapped in the applicative context.
811	///
812	/// # Examples
813	///
814	/// ```
815	/// use fp_library::classes::traversable::sequence;
816	/// use fp_library::brands::{PairWithSecondBrand, OptionBrand};
817	/// use fp_library::types::Pair;
818	///
819	/// assert_eq!(
820	///     sequence::<PairWithSecondBrand<()>, OptionBrand, _>(Pair(Some(5), ())),
821	///     Some(Pair(5, ()))
822	/// );
823	/// ```
824	fn sequence<'a, F: Applicative, A: 'a + Clone>(
825		ta: Apply!(brand: Self, signature: ('a, Apply!(brand: F, signature: ('a, A: 'a) -> 'a): 'a) -> 'a)
826	) -> Apply!(brand: F, signature: ('a, Apply!(brand: Self, signature: ('a, A: 'a) -> 'a): 'a) -> 'a)
827	where
828		Apply!(brand: F, signature: ('a, A: 'a) -> 'a): Clone,
829		Apply!(brand: Self, signature: ('a, A: 'a) -> 'a): Clone,
830	{
831		let Pair(first, second) = ta;
832		F::map(move |a| Pair(a, second.clone()), first)
833	}
834}
835
836#[cfg(test)]
837mod tests {
838	use super::*;
839	use crate::{
840		brands::{PairWithFirstBrand, RcFnBrand},
841		classes::{
842			clonable_fn::ClonableFn, functor::map, pointed::pure, semiapplicative::apply,
843			semimonad::bind,
844		},
845		functions::{compose, identity},
846	};
847	use quickcheck_macros::quickcheck;
848
849	// Functor Laws
850
851	/// Tests the identity law for Functor.
852	#[quickcheck]
853	fn functor_identity(
854		first: String,
855		second: i32,
856	) -> bool {
857		let x = Pair(first, second);
858		map::<PairWithFirstBrand<String>, _, _, _>(identity, x.clone()) == x
859	}
860
861	/// Tests the composition law for Functor.
862	#[quickcheck]
863	fn functor_composition(
864		first: String,
865		second: i32,
866	) -> bool {
867		let x = Pair(first, second);
868		let f = |x: i32| x.wrapping_add(1);
869		let g = |x: i32| x.wrapping_mul(2);
870		map::<PairWithFirstBrand<String>, _, _, _>(compose(f, g), x.clone())
871			== map::<PairWithFirstBrand<String>, _, _, _>(
872				f,
873				map::<PairWithFirstBrand<String>, _, _, _>(g, x),
874			)
875	}
876
877	// Applicative Laws
878
879	/// Tests the identity law for Applicative.
880	#[quickcheck]
881	fn applicative_identity(
882		first: String,
883		second: i32,
884	) -> bool {
885		let v = Pair(first, second);
886		apply::<PairWithFirstBrand<String>, _, _, RcFnBrand>(
887			pure::<PairWithFirstBrand<String>, _>(<RcFnBrand as ClonableFn>::new(identity)),
888			v.clone(),
889		) == v
890	}
891
892	/// Tests the homomorphism law for Applicative.
893	#[quickcheck]
894	fn applicative_homomorphism(x: i32) -> bool {
895		let f = |x: i32| x.wrapping_mul(2);
896		apply::<PairWithFirstBrand<String>, _, _, RcFnBrand>(
897			pure::<PairWithFirstBrand<String>, _>(<RcFnBrand as ClonableFn>::new(f)),
898			pure::<PairWithFirstBrand<String>, _>(x),
899		) == pure::<PairWithFirstBrand<String>, _>(f(x))
900	}
901
902	/// Tests the composition law for Applicative.
903	#[quickcheck]
904	fn applicative_composition(
905		w_first: String,
906		w_second: i32,
907		u_seed: i32,
908		v_seed: i32,
909	) -> bool {
910		let w = Pair(w_first, w_second);
911
912		let u_fn = <RcFnBrand as ClonableFn>::new(move |x: i32| x.wrapping_add(u_seed));
913		let u = pure::<PairWithFirstBrand<String>, _>(u_fn);
914
915		let v_fn = <RcFnBrand as ClonableFn>::new(move |x: i32| x.wrapping_mul(v_seed));
916		let v = pure::<PairWithFirstBrand<String>, _>(v_fn);
917
918		// RHS: u <*> (v <*> w)
919		let vw = apply::<PairWithFirstBrand<String>, _, _, RcFnBrand>(v.clone(), w.clone());
920		let rhs = apply::<PairWithFirstBrand<String>, _, _, RcFnBrand>(u.clone(), vw);
921
922		// LHS: pure(compose) <*> u <*> v <*> w
923		let compose_fn = <RcFnBrand as ClonableFn>::new(|f: std::rc::Rc<dyn Fn(i32) -> i32>| {
924			let f = f.clone();
925			<RcFnBrand as ClonableFn>::new(move |g: std::rc::Rc<dyn Fn(i32) -> i32>| {
926				let f = f.clone();
927				let g = g.clone();
928				<RcFnBrand as ClonableFn>::new(move |x| f(g(x)))
929			})
930		});
931
932		let pure_compose = pure::<PairWithFirstBrand<String>, _>(compose_fn);
933		let u_applied = apply::<PairWithFirstBrand<String>, _, _, RcFnBrand>(pure_compose, u);
934		let uv = apply::<PairWithFirstBrand<String>, _, _, RcFnBrand>(u_applied, v);
935		let lhs = apply::<PairWithFirstBrand<String>, _, _, RcFnBrand>(uv, w);
936
937		lhs == rhs
938	}
939
940	/// Tests the interchange law for Applicative.
941	#[quickcheck]
942	fn applicative_interchange(
943		y: i32,
944		u_seed: i32,
945	) -> bool {
946		// u <*> pure y = pure ($ y) <*> u
947		let f = move |x: i32| x.wrapping_mul(u_seed);
948		let u = pure::<PairWithFirstBrand<String>, _>(<RcFnBrand as ClonableFn>::new(f));
949
950		let lhs = apply::<PairWithFirstBrand<String>, _, _, RcFnBrand>(
951			u.clone(),
952			pure::<PairWithFirstBrand<String>, _>(y),
953		);
954
955		let rhs_fn = <RcFnBrand as ClonableFn>::new(move |f: std::rc::Rc<dyn Fn(i32) -> i32>| f(y));
956		let rhs = apply::<PairWithFirstBrand<String>, _, _, RcFnBrand>(
957			pure::<PairWithFirstBrand<String>, _>(rhs_fn),
958			u,
959		);
960
961		lhs == rhs
962	}
963
964	// Monad Laws
965
966	/// Tests the left identity law for Monad.
967	#[quickcheck]
968	fn monad_left_identity(a: i32) -> bool {
969		let f = |x: i32| Pair("f".to_string(), x.wrapping_mul(2));
970		bind::<PairWithFirstBrand<String>, _, _, _>(pure::<PairWithFirstBrand<String>, _>(a), f)
971			== f(a)
972	}
973
974	/// Tests the right identity law for Monad.
975	#[quickcheck]
976	fn monad_right_identity(
977		first: String,
978		second: i32,
979	) -> bool {
980		let m = Pair(first, second);
981		bind::<PairWithFirstBrand<String>, _, _, _>(
982			m.clone(),
983			pure::<PairWithFirstBrand<String>, _>,
984		) == m
985	}
986
987	/// Tests the associativity law for Monad.
988	#[quickcheck]
989	fn monad_associativity(
990		first: String,
991		second: i32,
992	) -> bool {
993		let m = Pair(first, second);
994		let f = |x: i32| Pair("f".to_string(), x.wrapping_mul(2));
995		let g = |x: i32| Pair("g".to_string(), x.wrapping_add(1));
996		bind::<PairWithFirstBrand<String>, _, _, _>(
997			bind::<PairWithFirstBrand<String>, _, _, _>(m.clone(), f),
998			g,
999		) == bind::<PairWithFirstBrand<String>, _, _, _>(m, |x| {
1000			bind::<PairWithFirstBrand<String>, _, _, _>(f(x), g)
1001		})
1002	}
1003}