fp_library/types/
pair.rs

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