fp_library/types/pair.rs
1//! Implementations for [`Pair`], a type that wraps two values.
2//!
3//! This module provides implementations of various type classes for the `Pair` type.
4//! `Pair` can be treated as a functor/monad in two ways:
5//! 1. `PairWithFirstBrand<First>`: Functor over the second value (fixing `First`).
6//! 2. `PairWithSecondBrand<Second>`: Functor over the first value (fixing `Second`).
7
8use crate::{
9 Apply,
10 brands::{PairBrand, PairWithFirstBrand, PairWithSecondBrand},
11 classes::{
12 applicative::Applicative, apply_first::ApplyFirst, apply_second::ApplySecond,
13 cloneable_fn::CloneableFn, foldable::Foldable, functor::Functor, lift::Lift,
14 monoid::Monoid, par_foldable::ParFoldable, pointed::Pointed,
15 semiapplicative::Semiapplicative, semigroup::Semigroup, semimonad::Semimonad,
16 send_cloneable_fn::SendCloneableFn, traversable::Traversable,
17 },
18 impl_kind,
19 kinds::*,
20};
21
22/// Wraps two values.
23///
24/// A simple tuple struct that holds two values of potentially different types.
25///
26/// ### Type Parameters
27///
28/// * `First`: The type of the first value.
29/// * `Second`: The type of the second value.
30///
31/// ### Fields
32///
33/// * `0`: The first value.
34/// * `1`: The second value.
35///
36/// ### Examples
37///
38/// ```
39/// use fp_library::types::*;
40///
41/// let p = Pair(1, "hello");
42/// assert_eq!(p.0, 1);
43/// assert_eq!(p.1, "hello");
44/// ```
45#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
46pub struct Pair<First, Second>(pub First, pub Second);
47
48impl_kind! {
49 for PairBrand {
50 type Of<A, B> = Pair<A, B>;
51 }
52}
53
54// PairWithFirstBrand<First> (Functor over Second)
55
56impl_kind! {
57 impl<First: 'static> for PairWithFirstBrand<First> {
58 type Of<'a, A: 'a>: 'a = Pair<First, A>;
59 }
60}
61
62impl<First: 'static> Functor for PairWithFirstBrand<First> {
63 /// Maps a function over the second value in the pair.
64 ///
65 /// This method applies a function to the second value inside the pair, producing a new pair with the transformed second value. The first value remains unchanged.
66 ///
67 /// ### Type Signature
68 ///
69 /// `forall t b a. Functor (Pair t) => (a -> b, Pair t a) -> Pair t b`
70 ///
71 /// ### Type Parameters
72 ///
73 /// * `B`: The type of the result of applying the function.
74 /// * `A`: The type of the second value.
75 /// * `F`: The type of the function to apply.
76 ///
77 /// ### Parameters
78 ///
79 /// * `f`: The function to apply to the second value.
80 /// * `fa`: The pair to map over.
81 ///
82 /// ### Returns
83 ///
84 /// A new pair containing the result of applying the function to the second value.
85 ///
86 /// ### Examples
87 ///
88 /// ```
89 /// use fp_library::{brands::*, functions::*, types::*};
90 ///
91 /// assert_eq!(map::<PairWithFirstBrand<_>, _, _, _>(|x: i32| x * 2, Pair(1, 5)), Pair(1, 10));
92 /// ```
93 fn map<'a, B: 'a, A: 'a, F>(
94 f: F,
95 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
96 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
97 where
98 F: Fn(A) -> B + 'a,
99 {
100 Pair(fa.0, f(fa.1))
101 }
102}
103
104impl<First: Clone + 'static> Lift for PairWithFirstBrand<First>
105where
106 First: Semigroup,
107{
108 /// Lifts a binary function into the pair context (over second).
109 ///
110 /// This method lifts a binary function to operate on the second values within the pair context. The first values are combined using their `Semigroup` implementation.
111 ///
112 /// ### Type Signature
113 ///
114 /// `forall t c a b. (Lift (Pair t), Semigroup t) => ((a, b) -> c, Pair t a, Pair t b) -> Pair t c`
115 ///
116 /// ### Type Parameters
117 ///
118 /// * `C`: The type of the result second value.
119 /// * `A`: The type of the first second value.
120 /// * `B`: The type of the second second value.
121 /// * `F`: The type of the binary function.
122 ///
123 /// ### Parameters
124 ///
125 /// * `f`: The binary function to apply to the second values.
126 /// * `fa`: The first pair.
127 /// * `fb`: The second pair.
128 ///
129 /// ### Returns
130 ///
131 /// A new pair where the first values are combined using `Semigroup::append` and the second values are combined using `f`.
132 ///
133 /// ### Examples
134 ///
135 /// ```
136 /// use fp_library::{brands::*, functions::*, types::*};
137 ///
138 /// assert_eq!(
139 /// lift2::<PairWithFirstBrand<String>, _, _, _, _>(|x, y| x + y, Pair("a".to_string(), 1), Pair("b".to_string(), 2)),
140 /// Pair("ab".to_string(), 3)
141 /// );
142 /// ```
143 fn lift2<'a, C, A, B, F>(
144 f: F,
145 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
146 fb: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>),
147 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>)
148 where
149 F: Fn(A, B) -> C + 'a,
150 A: Clone + 'a,
151 B: Clone + 'a,
152 C: 'a,
153 {
154 Pair(Semigroup::append(fa.0, fb.0), f(fa.1, fb.1))
155 }
156}
157
158impl<First: Clone + 'static> Pointed for PairWithFirstBrand<First>
159where
160 First: Monoid,
161{
162 /// Wraps a value in a pair (with empty first).
163 ///
164 /// This method wraps a value in a pair, using the `Monoid::empty()` value for the first element.
165 ///
166 /// ### Type Signature
167 ///
168 /// `forall t a. (Pointed (Pair t), Monoid t) => a -> Pair t a`
169 ///
170 /// ### Type Parameters
171 ///
172 /// * `A`: The type of the value to wrap.
173 ///
174 /// ### Parameters
175 ///
176 /// * `a`: The value to wrap.
177 ///
178 /// ### Returns
179 ///
180 /// A pair containing the empty value of the first type and `a`.
181 ///
182 /// ### Examples
183 ///
184 /// ```
185 /// use fp_library::{brands::*, functions::*, types::*};
186 ///
187 /// assert_eq!(pure::<PairWithFirstBrand<String>, _>(5), Pair("".to_string(), 5));
188 /// ```
189 fn pure<'a, A: 'a>(a: A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
190 Pair(Monoid::empty(), a)
191 }
192}
193
194impl<First: Clone + Semigroup + 'static> ApplyFirst for PairWithFirstBrand<First> {}
195impl<First: Clone + Semigroup + 'static> ApplySecond for PairWithFirstBrand<First> {}
196
197impl<First: Clone + 'static> Semiapplicative for PairWithFirstBrand<First>
198where
199 First: Semigroup,
200{
201 /// Applies a wrapped function to a wrapped value (over second).
202 ///
203 /// This method applies a function wrapped in a pair to a value wrapped in a pair. The first values are combined using their `Semigroup` implementation.
204 ///
205 /// ### Type Signature
206 ///
207 /// `forall fn_brand t b a. (Semiapplicative (Pair t), Semigroup t) => (Pair t (fn_brand a b), Pair t a) -> Pair t b`
208 ///
209 /// ### Type Parameters
210 ///
211 /// * `FnBrand`: The brand of the cloneable function wrapper.
212 /// * `B`: The type of the output value.
213 /// * `A`: The type of the input value.
214 ///
215 /// ### Parameters
216 ///
217 /// * `ff`: The pair containing the function.
218 /// * `fa`: The pair containing the value.
219 ///
220 /// ### Returns
221 ///
222 /// A new pair where the first values are combined and the function is applied to the second value.
223 ///
224 /// ### Examples
225 ///
226 /// ```
227 /// use fp_library::{brands::*, functions::*, types::*};
228 ///
229 /// let f = Pair("a".to_string(), cloneable_fn_new::<RcFnBrand, _, _>(|x: i32| x * 2));
230 /// assert_eq!(apply::<RcFnBrand, PairWithFirstBrand<String>, _, _>(f, Pair("b".to_string(), 5)), Pair("ab".to_string(), 10));
231 /// ```
232 fn apply<'a, FnBrand: 'a + CloneableFn, B: 'a, A: 'a + Clone>(
233 ff: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as CloneableFn>::Of<'a, A, B>>),
234 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
235 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
236 Pair(Semigroup::append(ff.0, fa.0), ff.1(fa.1))
237 }
238}
239
240impl<First: Clone + 'static> Semimonad for PairWithFirstBrand<First>
241where
242 First: Semigroup,
243{
244 /// Chains pair computations (over second).
245 ///
246 /// This method chains two computations, where the second computation depends on the result of the first. The first values are combined using their `Semigroup` implementation.
247 ///
248 /// ### Type Signature
249 ///
250 /// `forall t b a. (Semimonad (Pair t), Semigroup t) => (Pair t a, a -> Pair t b) -> Pair t b`
251 ///
252 /// ### Type Parameters
253 ///
254 /// * `B`: The type of the result of the second computation.
255 /// * `A`: The type of the result of the first computation.
256 /// * `F`: The type of the function to apply.
257 ///
258 /// ### Parameters
259 ///
260 /// * `ma`: The first pair.
261 /// * `f`: The function to apply to the second value.
262 ///
263 /// ### Returns
264 ///
265 /// A new pair where the first values are combined.
266 ///
267 /// ### Examples
268 ///
269 /// ```
270 /// use fp_library::{brands::*, functions::*, types::*};
271 ///
272 /// assert_eq!(
273 /// bind::<PairWithFirstBrand<String>, _, _, _>(Pair("a".to_string(), 5), |x| Pair("b".to_string(), x * 2)),
274 /// Pair("ab".to_string(), 10)
275 /// );
276 /// ```
277 fn bind<'a, B: 'a, A: 'a, F>(
278 ma: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
279 f: F,
280 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
281 where
282 F: Fn(A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
283 {
284 let Pair(first, second) = ma;
285 let Pair(next_first, next_second) = f(second);
286 Pair(Semigroup::append(first, next_first), next_second)
287 }
288}
289
290impl<First: 'static> Foldable for PairWithFirstBrand<First> {
291 /// Folds the pair from the right (over second).
292 ///
293 /// This method performs a right-associative fold of the pair (over second).
294 ///
295 /// ### Type Signature
296 ///
297 /// `forall t b a. Foldable (Pair t) => ((a, b) -> b, b, Pair t a) -> b`
298 ///
299 /// ### Type Parameters
300 ///
301 /// * `FnBrand`: The brand of the cloneable function to use.
302 /// * `B`: The type of the accumulator.
303 /// * `A`: The type of the elements in the structure.
304 /// * `Func`: The type of the folding function.
305 ///
306 /// ### Parameters
307 ///
308 /// * `func`: The folding function.
309 /// * `initial`: The initial value.
310 /// * `fa`: The pair to fold.
311 ///
312 /// ### Returns
313 ///
314 /// `func(a, initial)`.
315 ///
316 /// ### Examples
317 ///
318 /// ```
319 /// use fp_library::{brands::*, functions::*, types::*};
320 ///
321 /// assert_eq!(fold_right::<RcFnBrand, PairWithFirstBrand<()>, _, _, _>(|x, acc| x + acc, 0, Pair((), 5)), 5);
322 /// ```
323 fn fold_right<'a, FnBrand, B: 'a, A: 'a, Func>(
324 func: Func,
325 initial: B,
326 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
327 ) -> B
328 where
329 Func: Fn(A, B) -> B + 'a,
330 FnBrand: CloneableFn + 'a,
331 {
332 func(fa.1, initial)
333 }
334
335 /// Folds the pair from the left (over second).
336 ///
337 /// This method performs a left-associative fold of the pair (over second).
338 ///
339 /// ### Type Signature
340 ///
341 /// `forall t b a. Foldable (Pair t) => ((b, a) -> b, b, Pair t a) -> b`
342 ///
343 /// ### Type Parameters
344 ///
345 /// * `FnBrand`: The brand of the cloneable function to use.
346 /// * `B`: The type of the accumulator.
347 /// * `A`: The type of the elements in the structure.
348 /// * `Func`: The type of the folding function.
349 ///
350 /// ### Parameters
351 ///
352 /// * `func`: The function to apply to the accumulator and each element.
353 /// * `initial`: The initial value of the accumulator.
354 /// * `fa`: The identity to fold.
355 ///
356 /// ### Returns
357 ///
358 /// `func(initial, a)`.
359 ///
360 /// ### Examples
361 ///
362 /// ```
363 /// use fp_library::{brands::*, functions::*, types::*};
364 ///
365 /// assert_eq!(fold_left::<RcFnBrand, PairWithFirstBrand<()>, _, _, _>(|acc, x| acc + x, 0, Pair((), 5)), 5);
366 /// ```
367 fn fold_left<'a, FnBrand, B: 'a, A: 'a, Func>(
368 func: Func,
369 initial: B,
370 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
371 ) -> B
372 where
373 Func: Fn(B, A) -> B + 'a,
374 FnBrand: CloneableFn + 'a,
375 {
376 func(initial, fa.1)
377 }
378
379 /// Maps the value to a monoid and returns it (over second).
380 ///
381 /// This method maps the element of the pair to a monoid and then returns it (over second).
382 ///
383 /// ### Type Signature
384 ///
385 /// `forall t m a. (Foldable (Pair t), Monoid m) => ((a) -> m, Pair t a) -> m`
386 ///
387 /// ### Type Parameters
388 ///
389 /// * `FnBrand`: The brand of the cloneable function to use.
390 /// * `M`: The type of the monoid.
391 /// * `A`: The type of the elements in the structure.
392 /// * `Func`: The type of the mapping function.
393 ///
394 /// ### Parameters
395 ///
396 /// * `func`: The mapping function.
397 /// * `fa`: The pair to fold.
398 ///
399 /// ### Returns
400 ///
401 /// `func(a)`.
402 ///
403 /// ### Examples
404 ///
405 /// ```
406 /// use fp_library::{brands::*, functions::*, types::*};
407 ///
408 /// assert_eq!(
409 /// fold_map::<RcFnBrand, PairWithFirstBrand<()>, _, _, _>(|x: i32| x.to_string(), Pair((), 5)),
410 /// "5".to_string()
411 /// );
412 /// ```
413 fn fold_map<'a, FnBrand, M, A: 'a, Func>(
414 func: Func,
415 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
416 ) -> M
417 where
418 M: Monoid + 'a,
419 Func: Fn(A) -> M + 'a,
420 FnBrand: CloneableFn + 'a,
421 {
422 func(fa.1)
423 }
424}
425
426impl<First: Clone + 'static> Traversable for PairWithFirstBrand<First> {
427 /// Traverses the pair with an applicative function (over second).
428 ///
429 /// This method maps the element of the pair to a computation, evaluates it, and combines the result into an applicative context (over second).
430 ///
431 /// ### Type Signature
432 ///
433 /// `forall t f b a. (Traversable (Pair t), Applicative f) => (a -> f b, Pair t a) -> f (Pair t b)`
434 ///
435 /// ### Type Parameters
436 ///
437 /// * `F`: The applicative context.
438 /// * `B`: The type of the elements in the resulting traversable structure.
439 /// * `A`: The type of the elements in the traversable structure.
440 /// * `Func`: The type of the function to apply.
441 ///
442 /// ### Parameters
443 ///
444 /// * `func`: The function to apply to each element, returning a value in an applicative context.
445 /// * `ta`: The pair to traverse.
446 ///
447 /// ### Returns
448 ///
449 /// The pair wrapped in the applicative context.
450 ///
451 /// ### Examples
452 ///
453 /// ```
454 /// use fp_library::{brands::*, functions::*, types::*};
455 ///
456 /// assert_eq!(
457 /// traverse::<PairWithFirstBrand<()>, OptionBrand, _, _, _>(|x| Some(x * 2), Pair((), 5)),
458 /// Some(Pair((), 10))
459 /// );
460 /// ```
461 fn traverse<'a, F: Applicative, B: 'a + Clone, A: 'a + Clone, Func>(
462 func: Func,
463 ta: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
464 ) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)>)
465 where
466 Func: Fn(A) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
467 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>): Clone,
468 {
469 let Pair(first, second) = ta;
470 F::map(move |b| Pair(first.clone(), b), func(second))
471 }
472 /// Sequences a pair of applicative (over second).
473 ///
474 /// This method evaluates the computation inside the pair and accumulates the result into an applicative context (over second).
475 ///
476 /// ### Type Signature
477 ///
478 /// `forall t f a. (Traversable (Pair t), Applicative f) => (Pair t (f a)) -> f (Pair t a)`
479 ///
480 /// ### Type Parameters
481 ///
482 /// * `F`: The applicative context.
483 /// * `A`: The type of the elements in the traversable structure.
484 ///
485 /// ### Parameters
486 ///
487 /// * `ta`: The pair containing the applicative value.
488 ///
489 /// ### Returns
490 ///
491 /// The pair wrapped in the applicative context.
492 ///
493 /// ### Examples
494 ///
495 /// ```
496 /// use fp_library::{brands::*, functions::*, types::*};
497 ///
498 /// assert_eq!(
499 /// sequence::<PairWithFirstBrand<()>, OptionBrand, _>(Pair((), Some(5))),
500 /// Some(Pair((), 5))
501 /// );
502 /// ```
503 fn sequence<'a, F: Applicative, A: 'a + Clone>(
504 ta: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)>)
505 ) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)>)
506 where
507 Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>): Clone,
508 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>): Clone,
509 {
510 let Pair(first, second) = ta;
511 F::map(move |a| Pair(first.clone(), a), second)
512 }
513}
514
515impl<First: 'static, FnBrand: SendCloneableFn> ParFoldable<FnBrand> for PairWithFirstBrand<First> {
516 /// Maps the value to a monoid and returns it in parallel (over second).
517 ///
518 /// This method maps the element of the pair to a monoid and then returns it (over second). The mapping operation may be executed in parallel.
519 ///
520 /// ### Type Signature
521 ///
522 /// `forall fn_brand t m a. (ParFoldable (Pair t), Monoid m, Send m, Sync m) => (fn_brand a m, Pair t a) -> m`
523 ///
524 /// ### Type Parameters
525 ///
526 /// * `M`: The monoid type (must be `Send + Sync`).
527 /// * `A`: The element type (must be `Send + Sync`).
528 ///
529 /// ### Parameters
530 ///
531 /// * `func`: The thread-safe function to map each element to a monoid.
532 /// * `fa`: The pair to fold.
533 ///
534 /// ### Returns
535 ///
536 /// The combined monoid value.
537 ///
538 /// ### Examples
539 ///
540 /// ```
541 /// use fp_library::{brands::*, functions::*, types::*};
542 ///
543 /// let x = Pair("a".to_string(), 1);
544 /// let f = send_cloneable_fn_new::<ArcFnBrand, _, _>(|x: i32| x.to_string());
545 /// assert_eq!(
546 /// par_fold_map::<ArcFnBrand, PairWithFirstBrand<String>, _, _>(f, x),
547 /// "1".to_string()
548 /// );
549 /// ```
550 fn par_fold_map<'a, M, A>(
551 func: <FnBrand as SendCloneableFn>::SendOf<'a, A, M>,
552 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
553 ) -> M
554 where
555 A: 'a + Clone + Send + Sync,
556 M: Monoid + Send + Sync + 'a,
557 {
558 func(fa.1)
559 }
560
561 /// Folds the pair from the right in parallel (over second).
562 ///
563 /// This method folds the pair by applying a function from right to left, potentially in parallel (over second).
564 ///
565 /// ### Type Signature
566 ///
567 /// `forall fn_brand t b a. ParFoldable (Pair t) => (fn_brand (a, b) b, b, Pair t a) -> b`
568 ///
569 /// ### Type Parameters
570 ///
571 /// * `B`: The accumulator type (must be `Send + Sync`).
572 /// * `A`: The element type (must be `Send + Sync`).
573 ///
574 /// ### Parameters
575 ///
576 /// * `func`: The thread-safe function to apply to each element and the accumulator.
577 /// * `initial`: The initial value.
578 /// * `fa`: The pair to fold.
579 ///
580 /// ### Returns
581 ///
582 /// The final accumulator value.
583 ///
584 /// ### Examples
585 ///
586 /// ```
587 /// use fp_library::{brands::*, functions::*, types::*};
588 ///
589 /// let x = Pair("a".to_string(), 1);
590 /// let f = send_cloneable_fn_new::<ArcFnBrand, _, _>(|(a, b): (i32, i32)| a + b);
591 /// assert_eq!(par_fold_right::<ArcFnBrand, PairWithFirstBrand<String>, _, _>(f, 10, x), 11);
592 /// ```
593 fn par_fold_right<'a, B, A>(
594 func: <FnBrand as SendCloneableFn>::SendOf<'a, (A, B), B>,
595 initial: B,
596 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
597 ) -> B
598 where
599 A: 'a + Clone + Send + Sync,
600 B: Send + Sync + 'a,
601 {
602 func((fa.1, initial))
603 }
604}
605// PairWithSecondBrand<Second> (Functor over First)
606
607impl_kind! {
608 impl<Second: 'static> for PairWithSecondBrand<Second> {
609 type Of<'a, A: 'a>: 'a = Pair<A, Second>;
610 }
611}
612
613impl<Second: 'static> Functor for PairWithSecondBrand<Second> {
614 /// Maps a function over the first value in the pair.
615 ///
616 /// This method applies a function to the first value inside the pair, producing a new pair with the transformed first value. The second value remains unchanged.
617 ///
618 /// ### Type Signature
619 ///
620 /// `forall t b a. Functor (PairWithSecond t) => (a -> b, Pair a t) -> Pair b t`
621 ///
622 /// ### Type Parameters
623 ///
624 /// * `B`: The type of the result of applying the function.
625 /// * `A`: The type of the first value.
626 /// * `F`: The type of the function to apply.
627 ///
628 /// ### Parameters
629 ///
630 /// * `f`: The function to apply to the first value.
631 /// * `fa`: The pair to map over.
632 ///
633 /// ### Returns
634 ///
635 /// A new pair containing the result of applying the function to the first value.
636 ///
637 /// ### Examples
638 ///
639 /// ```
640 /// use fp_library::{brands::*, functions::*, types::*};
641 ///
642 /// assert_eq!(map::<PairWithSecondBrand<_>, _, _, _>(|x: i32| x * 2, Pair(5, 1)), Pair(10, 1));
643 /// ```
644 fn map<'a, B: 'a, A: 'a, F>(
645 f: F,
646 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
647 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
648 where
649 F: Fn(A) -> B + 'a,
650 {
651 Pair(f(fa.0), fa.1)
652 }
653}
654
655impl<Second: Clone + 'static> Lift for PairWithSecondBrand<Second>
656where
657 Second: Semigroup,
658{
659 /// Lifts a binary function into the pair context (over first).
660 ///
661 /// This method lifts a binary function to operate on the first values within the pair context. The second values are combined using their `Semigroup` implementation.
662 ///
663 /// ### Type Signature
664 ///
665 /// `forall t c a b. (Lift (PairWithSecond t), Semigroup t) => ((a, b) -> c, Pair a t, Pair b t) -> Pair c t`
666 ///
667 /// ### Type Parameters
668 ///
669 /// * `C`: The type of the result first value.
670 /// * `A`: The type of the first first value.
671 /// * `B`: The type of the second first value.
672 /// * `F`: The type of the binary function.
673 ///
674 /// ### Parameters
675 ///
676 /// * `f`: The binary function to apply to the first values.
677 /// * `fa`: The first pair.
678 /// * `fb`: The second pair.
679 ///
680 /// ### Returns
681 ///
682 /// A new pair where the first values are combined using `f` and the second values are combined using `Semigroup::append`.
683 ///
684 /// ### Examples
685 ///
686 /// ```
687 /// use fp_library::{brands::*, functions::*, types::*};
688 ///
689 /// assert_eq!(
690 /// lift2::<PairWithSecondBrand<String>, _, _, _, _>(|x, y| x + y, Pair(1, "a".to_string()), Pair(2, "b".to_string())),
691 /// Pair(3, "ab".to_string())
692 /// );
693 /// ```
694 fn lift2<'a, C, A, B, F>(
695 f: F,
696 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
697 fb: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>),
698 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>)
699 where
700 F: Fn(A, B) -> C + 'a,
701 A: Clone + 'a,
702 B: Clone + 'a,
703 C: 'a,
704 {
705 Pair(f(fa.0, fb.0), Semigroup::append(fa.1, fb.1))
706 }
707}
708
709impl<Second: Clone + 'static> Pointed for PairWithSecondBrand<Second>
710where
711 Second: Monoid,
712{
713 /// Wraps a value in a pair (with empty second).
714 ///
715 /// This method wraps a value in a pair, using the `Monoid::empty()` value for the second element.
716 ///
717 /// ### Type Signature
718 ///
719 /// `forall t a. (Pointed (PairWithSecond t), Monoid t) => a -> Pair a t`
720 ///
721 /// ### Type Parameters
722 ///
723 /// * `A`: The type of the value to wrap.
724 ///
725 /// ### Parameters
726 ///
727 /// * `a`: The value to wrap.
728 ///
729 /// ### Returns
730 ///
731 /// A pair containing `a` and the empty value of the second type.
732 ///
733 /// ### Examples
734 ///
735 /// ```
736 /// use fp_library::{brands::*, functions::*, types::*};
737 ///
738 /// assert_eq!(pure::<PairWithSecondBrand<String>, _>(5), Pair(5, "".to_string()));
739 /// ```
740 fn pure<'a, A: 'a>(a: A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
741 Pair(a, Monoid::empty())
742 }
743}
744
745impl<Second: Clone + Semigroup + 'static> ApplyFirst for PairWithSecondBrand<Second> {}
746impl<Second: Clone + Semigroup + 'static> ApplySecond for PairWithSecondBrand<Second> {}
747
748impl<Second: Clone + 'static> Semiapplicative for PairWithSecondBrand<Second>
749where
750 Second: Semigroup,
751{
752 /// Applies a wrapped function to a wrapped value (over first).
753 ///
754 /// This method applies a function wrapped in a result (as error) to a value wrapped in a result (as error).
755 ///
756 /// ### Type Signature
757 ///
758 /// `forall fn_brand t b a. (Semiapplicative (PairWithSecond t), Semigroup t) => (Pair (fn_brand a b) t, Pair a t) -> Pair b t`
759 ///
760 /// ### Type Parameters
761 ///
762 /// * `FnBrand`: The brand of the cloneable function wrapper.
763 /// * `B`: The type of the output value.
764 /// * `A`: The type of the input value.
765 ///
766 /// ### Parameters
767 ///
768 /// * `ff`: The pair containing the function (in Err).
769 /// * `fa`: The pair containing the value (in Err).
770 ///
771 /// ### Returns
772 ///
773 /// `Err(f(a))` if both are `Err`, otherwise the first success encountered.
774 ///
775 /// ### Examples
776 ///
777 /// ```
778 /// use fp_library::{brands::*, functions::*, types::*};
779 ///
780 /// let f = Pair(cloneable_fn_new::<RcFnBrand, _, _>(|x: i32| x * 2), "a".to_string());
781 /// assert_eq!(apply::<RcFnBrand, PairWithSecondBrand<String>, _, _>(f, Pair(5, "b".to_string())), Pair(10, "ab".to_string()));
782 /// ```
783 fn apply<'a, FnBrand: 'a + CloneableFn, B: 'a, A: 'a + Clone>(
784 ff: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as CloneableFn>::Of<'a, A, B>>),
785 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
786 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
787 Pair(ff.0(fa.0), Semigroup::append(ff.1, fa.1))
788 }
789}
790
791impl<Second: Clone + 'static> Semimonad for PairWithSecondBrand<Second>
792where
793 Second: Semigroup,
794{
795 /// Chains pair computations (over first).
796 ///
797 /// This method chains two computations, where the second computation depends on the result of the first (over error).
798 ///
799 /// ### Type Signature
800 ///
801 /// `forall t b a. (Semimonad (PairWithSecond t), Semigroup t) => (Pair a t, a -> Pair b t) -> Pair b t`
802 ///
803 /// ### Type Parameters
804 ///
805 /// * `B`: The type of the result of the second computation.
806 /// * `A`: The type of the result of the first computation.
807 /// * `F`: The type of the function to apply.
808 ///
809 /// ### Parameters
810 ///
811 /// * `ma`: The first result.
812 /// * `f`: The function to apply to the error value.
813 ///
814 /// ### Returns
815 ///
816 /// The result of applying `f` to the error if `ma` is `Err`, otherwise the original success.
817 ///
818 /// ### Examples
819 ///
820 /// ```
821 /// use fp_library::{brands::*, functions::*, types::*};
822 ///
823 /// assert_eq!(
824 /// bind::<PairWithSecondBrand<String>, _, _, _>(Pair(5, "a".to_string()), |x| Pair(x * 2, "b".to_string())),
825 /// Pair(10, "ab".to_string())
826 /// );
827 /// ```
828 fn bind<'a, B: 'a, A: 'a, F>(
829 ma: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
830 f: F,
831 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
832 where
833 F: Fn(A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
834 {
835 let Pair(first, second) = ma;
836 let Pair(next_first, next_second) = f(first);
837 Pair(next_first, Semigroup::append(second, next_second))
838 }
839}
840
841impl<Second: 'static> Foldable for PairWithSecondBrand<Second> {
842 /// Folds the pair from the right (over first).
843 ///
844 /// This method performs a right-associative fold of the result (over error).
845 ///
846 /// ### Type Signature
847 ///
848 /// `forall t b a. Foldable (PairWithSecond t) => ((a, b) -> b, b, Pair a t) -> b`
849 ///
850 /// ### Type Parameters
851 ///
852 /// * `FnBrand`: The brand of the cloneable function to use.
853 /// * `B`: The type of the accumulator.
854 /// * `A`: The type of the elements in the structure.
855 /// * `F`: The type of the folding function.
856 ///
857 /// ### Parameters
858 ///
859 /// * `func`: The folding function.
860 /// * `initial`: The initial value.
861 /// * `fa`: The result to fold.
862 ///
863 /// ### Returns
864 ///
865 /// `func(a, initial)` if `fa` is `Err(a)`, otherwise `initial`.
866 ///
867 /// ### Examples
868 ///
869 /// ```
870 /// use fp_library::{brands::*, functions::*, types::*};
871 ///
872 /// assert_eq!(fold_right::<RcFnBrand, PairWithSecondBrand<()>, _, _, _>(|x, acc| x + acc, 0, Pair(5, ())), 5);
873 /// ```
874 fn fold_right<'a, FnBrand, B: 'a, A: 'a, F>(
875 func: F,
876 initial: B,
877 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
878 ) -> B
879 where
880 F: Fn(A, B) -> B + 'a,
881 FnBrand: CloneableFn + 'a,
882 {
883 func(fa.0, initial)
884 }
885
886 /// Folds the pair from the left (over first).
887 ///
888 /// This method performs a left-associative fold of the result (over error).
889 ///
890 /// ### Type Signature
891 ///
892 /// `forall t b a. Foldable (PairWithSecond t) => ((b, a) -> b, b, Pair a t) -> b`
893 ///
894 /// ### Type Parameters
895 ///
896 /// * `FnBrand`: The brand of the cloneable function to use.
897 /// * `B`: The type of the accumulator.
898 /// * `A`: The type of the elements in the structure.
899 /// * `F`: The type of the folding function.
900 ///
901 /// ### Parameters
902 ///
903 /// * `func`: The folding function.
904 /// * `initial`: The initial value.
905 /// * `fa`: The result to fold.
906 ///
907 /// ### Returns
908 ///
909 /// `func(initial, a)` if `fa` is `Err(a)`, otherwise `initial`.
910 ///
911 /// ### Examples
912 ///
913 /// ```
914 /// use fp_library::{brands::*, functions::*, types::*};
915 ///
916 /// assert_eq!(fold_left::<RcFnBrand, PairWithSecondBrand<()>, _, _, _>(|acc, x| acc + x, 0, Pair(5, ())), 5);
917 /// ```
918 fn fold_left<'a, FnBrand, B: 'a, A: 'a, F>(
919 func: F,
920 initial: B,
921 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
922 ) -> B
923 where
924 F: Fn(B, A) -> B + 'a,
925 FnBrand: CloneableFn + 'a,
926 {
927 func(initial, fa.0)
928 }
929
930 /// Maps the value to a monoid and returns it (over first).
931 ///
932 /// This method maps the element of the result to a monoid and then returns it (over error).
933 ///
934 /// ### Type Signature
935 ///
936 /// `forall t m a. (Foldable (PairWithSecond t), Monoid m) => ((a) -> m, Pair a t) -> m`
937 ///
938 /// ### Type Parameters
939 ///
940 /// * `FnBrand`: The brand of the cloneable function to use.
941 /// * `M`: The type of the monoid.
942 /// * `A`: The type of the elements in the structure.
943 /// * `Func`: The type of the mapping function.
944 ///
945 /// ### Parameters
946 ///
947 /// * `func`: The mapping function.
948 /// * `fa`: The result to fold.
949 ///
950 /// ### Returns
951 ///
952 /// `func(a)` if `fa` is `Err(a)`, otherwise `M::empty()`.
953 ///
954 /// ### Examples
955 ///
956 /// ```
957 /// use fp_library::{brands::*, functions::*, types::*};
958 ///
959 /// assert_eq!(
960 /// fold_map::<RcFnBrand, PairWithSecondBrand<()>, _, _, _>(|x: i32| x.to_string(), Pair(5, ())),
961 /// "5".to_string()
962 /// );
963 /// ```
964 fn fold_map<'a, FnBrand, M, A: 'a, Func>(
965 func: Func,
966 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
967 ) -> M
968 where
969 M: Monoid + 'a,
970 Func: Fn(A) -> M + 'a,
971 FnBrand: CloneableFn + 'a,
972 {
973 func(fa.0)
974 }
975}
976
977impl<Second: Clone + 'static> Traversable for PairWithSecondBrand<Second> {
978 /// Traverses the pair with an applicative function (over first).
979 ///
980 /// This method maps the element of the result to a computation, evaluates it, and combines the result into an applicative context (over error).
981 ///
982 /// ### Type Signature
983 ///
984 /// `forall t f b a. (Traversable (PairWithSecond t), Applicative f) => (a -> f b, Pair a t) -> f (Pair b t)`
985 ///
986 /// ### Type Parameters
987 ///
988 /// * `F`: The applicative context.
989 /// * `B`: The type of the elements in the resulting traversable structure.
990 /// * `A`: The type of the elements in the traversable structure.
991 /// * `Func`: The type of the function to apply.
992 ///
993 /// ### Parameters
994 ///
995 /// * `func`: The function to apply.
996 /// * `ta`: The result to traverse.
997 ///
998 /// ### Returns
999 ///
1000 /// The result wrapped in the applicative context.
1001 ///
1002 /// ### Examples
1003 ///
1004 /// ```
1005 /// use fp_library::{brands::*, functions::*, types::*};
1006 ///
1007 /// assert_eq!(
1008 /// traverse::<PairWithSecondBrand<()>, OptionBrand, _, _, _>(|x| Some(x * 2), Pair(5, ())),
1009 /// Some(Pair(10, ()))
1010 /// );
1011 /// ```
1012 fn traverse<'a, F: Applicative, B: 'a + Clone, A: 'a + Clone, Func>(
1013 func: Func,
1014 ta: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1015 ) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)>)
1016 where
1017 Func: Fn(A) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
1018 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>): Clone,
1019 {
1020 let Pair(first, second) = ta;
1021 F::map(move |b| Pair(b, second.clone()), func(first))
1022 }
1023
1024 /// Sequences a pair of applicative (over first).
1025 ///
1026 /// This method evaluates the computation inside the result and accumulates the result into an applicative context (over error).
1027 ///
1028 /// ### Type Signature
1029 ///
1030 /// `forall t f a. (Traversable (PairWithSecond t), Applicative f) => (Pair (f a) t) -> f (Pair a t)`
1031 ///
1032 /// ### Type Parameters
1033 ///
1034 /// * `F`: The applicative context.
1035 /// * `A`: The type of the elements in the traversable structure.
1036 ///
1037 /// ### Parameters
1038 ///
1039 /// * `ta`: The result containing the applicative value.
1040 ///
1041 /// ### Returns
1042 ///
1043 /// The result wrapped in the applicative context.
1044 ///
1045 /// ### Examples
1046 ///
1047 /// ```
1048 /// use fp_library::{brands::*, functions::*, types::*};
1049 ///
1050 /// assert_eq!(
1051 /// sequence::<PairWithSecondBrand<()>, OptionBrand, _>(Pair(Some(5), ())),
1052 /// Some(Pair(5, ()))
1053 /// );
1054 /// ```
1055 fn sequence<'a, F: Applicative, A: 'a + Clone>(
1056 ta: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)>)
1057 ) -> Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>)>)
1058 where
1059 Apply!(<F as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>): Clone,
1060 Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>): Clone,
1061 {
1062 let Pair(first, second) = ta;
1063 F::map(move |a| Pair(a, second.clone()), first)
1064 }
1065}
1066
1067impl<Second: 'static, FnBrand: SendCloneableFn> ParFoldable<FnBrand>
1068 for PairWithSecondBrand<Second>
1069{
1070 /// Maps the value to a monoid and returns it in parallel (over first).
1071 ///
1072 /// This method maps the element of the pair to a monoid and then returns it (over first). The mapping operation may be executed in parallel.
1073 ///
1074 /// ### Type Signature
1075 ///
1076 /// `forall fn_brand t m a. (ParFoldable (PairWithSecond t), Monoid m, Send m, Sync m) => (fn_brand a m, Pair a t) -> m`
1077 ///
1078 /// ### Type Parameters
1079 ///
1080 /// * `M`: The monoid type (must be `Send + Sync`).
1081 /// * `A`: The element type (must be `Send + Sync`).
1082 ///
1083 /// ### Parameters
1084 ///
1085 /// * `func`: The thread-safe function to map each element to a monoid.
1086 /// * `fa`: The pair to fold.
1087 ///
1088 /// ### Returns
1089 ///
1090 /// The combined monoid value.
1091 ///
1092 /// ### Examples
1093 ///
1094 /// ```
1095 /// use fp_library::{brands::*, functions::*, types::*};
1096 ///
1097 /// let x = Pair(1, "a".to_string());
1098 /// let f = send_cloneable_fn_new::<ArcFnBrand, _, _>(|x: i32| x.to_string());
1099 /// assert_eq!(
1100 /// par_fold_map::<ArcFnBrand, PairWithSecondBrand<String>, _, _>(f, x),
1101 /// "1".to_string()
1102 /// );
1103 /// ```
1104 fn par_fold_map<'a, M, A>(
1105 func: <FnBrand as SendCloneableFn>::SendOf<'a, A, M>,
1106 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1107 ) -> M
1108 where
1109 A: 'a + Clone + Send + Sync,
1110 M: Monoid + Send + Sync + 'a,
1111 {
1112 func(fa.0)
1113 }
1114
1115 /// Folds the pair from the right in parallel (over first).
1116 ///
1117 /// This method folds the pair by applying a function from right to left, potentially in parallel (over first).
1118 ///
1119 /// ### Type Signature
1120 ///
1121 /// `forall fn_brand t b a. ParFoldable (PairWithSecond t) => (fn_brand (a, b) b, b, Pair a t) -> b`
1122 ///
1123 /// ### Type Parameters
1124 ///
1125 /// * `B`: The accumulator type (must be `Send + Sync`).
1126 /// * `A`: The element type (must be `Send + Sync`).
1127 ///
1128 /// ### Parameters
1129 ///
1130 /// * `func`: The thread-safe function to apply to each element and the accumulator.
1131 /// * `initial`: The initial value.
1132 /// * `fa`: The pair to fold.
1133 ///
1134 /// ### Returns
1135 ///
1136 /// The final accumulator value.
1137 ///
1138 /// ### Examples
1139 ///
1140 /// ```
1141 /// use fp_library::{brands::*, functions::*, types::*};
1142 ///
1143 /// let x = Pair(1, "a".to_string());
1144 /// let f = send_cloneable_fn_new::<ArcFnBrand, _, _>(|(a, b): (i32, i32)| a + b);
1145 /// assert_eq!(par_fold_right::<ArcFnBrand, PairWithSecondBrand<String>, _, _>(f, 10, x), 11);
1146 /// ```
1147 fn par_fold_right<'a, B, A>(
1148 func: <FnBrand as SendCloneableFn>::SendOf<'a, (A, B), B>,
1149 initial: B,
1150 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1151 ) -> B
1152 where
1153 A: 'a + Clone + Send + Sync,
1154 B: Send + Sync + 'a,
1155 {
1156 func((fa.0, initial))
1157 }
1158}
1159
1160#[cfg(test)]
1161mod tests {
1162 use super::*;
1163 use crate::{brands::*, functions::*};
1164 use quickcheck_macros::quickcheck;
1165
1166 // Functor Laws
1167
1168 /// Tests the identity law for Functor.
1169 #[quickcheck]
1170 fn functor_identity(
1171 first: String,
1172 second: i32,
1173 ) -> bool {
1174 let x = Pair(first, second);
1175 map::<PairWithFirstBrand<String>, _, _, _>(identity, x.clone()) == x
1176 }
1177
1178 /// Tests the composition law for Functor.
1179 #[quickcheck]
1180 fn functor_composition(
1181 first: String,
1182 second: i32,
1183 ) -> bool {
1184 let x = Pair(first, second);
1185 let f = |x: i32| x.wrapping_add(1);
1186 let g = |x: i32| x.wrapping_mul(2);
1187 map::<PairWithFirstBrand<String>, _, _, _>(compose(f, g), x.clone())
1188 == map::<PairWithFirstBrand<String>, _, _, _>(
1189 f,
1190 map::<PairWithFirstBrand<String>, _, _, _>(g, x),
1191 )
1192 }
1193
1194 // Applicative Laws
1195
1196 /// Tests the identity law for Applicative.
1197 #[quickcheck]
1198 fn applicative_identity(
1199 first: String,
1200 second: i32,
1201 ) -> bool {
1202 let v = Pair(first, second);
1203 apply::<RcFnBrand, PairWithFirstBrand<String>, _, _>(
1204 pure::<PairWithFirstBrand<String>, _>(<RcFnBrand as CloneableFn>::new(identity)),
1205 v.clone(),
1206 ) == v
1207 }
1208
1209 /// Tests the homomorphism law for Applicative.
1210 #[quickcheck]
1211 fn applicative_homomorphism(x: i32) -> bool {
1212 let f = |x: i32| x.wrapping_mul(2);
1213 apply::<RcFnBrand, PairWithFirstBrand<String>, _, _>(
1214 pure::<PairWithFirstBrand<String>, _>(<RcFnBrand as CloneableFn>::new(f)),
1215 pure::<PairWithFirstBrand<String>, _>(x),
1216 ) == pure::<PairWithFirstBrand<String>, _>(f(x))
1217 }
1218
1219 /// Tests the composition law for Applicative.
1220 #[quickcheck]
1221 fn applicative_composition(
1222 w_first: String,
1223 w_second: i32,
1224 u_seed: i32,
1225 v_seed: i32,
1226 ) -> bool {
1227 let w = Pair(w_first, w_second);
1228
1229 let u_fn = <RcFnBrand as CloneableFn>::new(move |x: i32| x.wrapping_add(u_seed));
1230 let u = pure::<PairWithFirstBrand<String>, _>(u_fn);
1231
1232 let v_fn = <RcFnBrand as CloneableFn>::new(move |x: i32| x.wrapping_mul(v_seed));
1233 let v = pure::<PairWithFirstBrand<String>, _>(v_fn);
1234
1235 // RHS: u <*> (v <*> w)
1236 let vw = apply::<RcFnBrand, PairWithFirstBrand<String>, _, _>(v.clone(), w.clone());
1237 let rhs = apply::<RcFnBrand, PairWithFirstBrand<String>, _, _>(u.clone(), vw);
1238
1239 // LHS: pure(compose) <*> u <*> v <*> w
1240 let compose_fn = <RcFnBrand as CloneableFn>::new(|f: std::rc::Rc<dyn Fn(i32) -> i32>| {
1241 let f = f.clone();
1242 <RcFnBrand as CloneableFn>::new(move |g: std::rc::Rc<dyn Fn(i32) -> i32>| {
1243 let f = f.clone();
1244 let g = g.clone();
1245 <RcFnBrand as CloneableFn>::new(move |x| f(g(x)))
1246 })
1247 });
1248
1249 let pure_compose = pure::<PairWithFirstBrand<String>, _>(compose_fn);
1250 let u_applied = apply::<RcFnBrand, PairWithFirstBrand<String>, _, _>(pure_compose, u);
1251 let uv = apply::<RcFnBrand, PairWithFirstBrand<String>, _, _>(u_applied, v);
1252 let lhs = apply::<RcFnBrand, PairWithFirstBrand<String>, _, _>(uv, w);
1253
1254 lhs == rhs
1255 }
1256
1257 /// Tests the interchange law for Applicative.
1258 #[quickcheck]
1259 fn applicative_interchange(
1260 y: i32,
1261 u_seed: i32,
1262 ) -> bool {
1263 // u <*> pure y = pure ($ y) <*> u
1264 let f = move |x: i32| x.wrapping_mul(u_seed);
1265 let u = pure::<PairWithFirstBrand<String>, _>(<RcFnBrand as CloneableFn>::new(f));
1266
1267 let lhs = apply::<RcFnBrand, PairWithFirstBrand<String>, _, _>(
1268 u.clone(),
1269 pure::<PairWithFirstBrand<String>, _>(y),
1270 );
1271
1272 let rhs_fn =
1273 <RcFnBrand as CloneableFn>::new(move |f: std::rc::Rc<dyn Fn(i32) -> i32>| f(y));
1274 let rhs = apply::<RcFnBrand, PairWithFirstBrand<String>, _, _>(
1275 pure::<PairWithFirstBrand<String>, _>(rhs_fn),
1276 u,
1277 );
1278
1279 lhs == rhs
1280 }
1281
1282 // Monad Laws
1283
1284 /// Tests the left identity law for Monad.
1285 #[quickcheck]
1286 fn monad_left_identity(a: i32) -> bool {
1287 let f = |x: i32| Pair("f".to_string(), x.wrapping_mul(2));
1288 bind::<PairWithFirstBrand<String>, _, _, _>(pure::<PairWithFirstBrand<String>, _>(a), f)
1289 == f(a)
1290 }
1291
1292 /// Tests the right identity law for Monad.
1293 #[quickcheck]
1294 fn monad_right_identity(
1295 first: String,
1296 second: i32,
1297 ) -> bool {
1298 let m = Pair(first, second);
1299 bind::<PairWithFirstBrand<String>, _, _, _>(
1300 m.clone(),
1301 pure::<PairWithFirstBrand<String>, _>,
1302 ) == m
1303 }
1304
1305 /// Tests the associativity law for Monad.
1306 #[quickcheck]
1307 fn monad_associativity(
1308 first: String,
1309 second: i32,
1310 ) -> bool {
1311 let m = Pair(first, second);
1312 let f = |x: i32| Pair("f".to_string(), x.wrapping_mul(2));
1313 let g = |x: i32| Pair("g".to_string(), x.wrapping_add(1));
1314 bind::<PairWithFirstBrand<String>, _, _, _>(
1315 bind::<PairWithFirstBrand<String>, _, _, _>(m.clone(), f),
1316 g,
1317 ) == bind::<PairWithFirstBrand<String>, _, _, _>(m, |x| {
1318 bind::<PairWithFirstBrand<String>, _, _, _>(f(x), g)
1319 })
1320 }
1321
1322 // ParFoldable Tests for PairWithFirstBrand (Functor over Second)
1323
1324 /// Tests `par_fold_map` on `PairWithFirstBrand`.
1325 #[test]
1326 fn par_fold_map_pair_with_first() {
1327 let x = Pair("a".to_string(), 1);
1328 let f = send_cloneable_fn_new::<ArcFnBrand, _, _>(|x: i32| x.to_string());
1329 assert_eq!(
1330 par_fold_map::<ArcFnBrand, PairWithFirstBrand<String>, _, _>(f, x),
1331 "1".to_string()
1332 );
1333 }
1334
1335 /// Tests `par_fold_right` on `PairWithFirstBrand`.
1336 #[test]
1337 fn par_fold_right_pair_with_first() {
1338 let x = Pair("a".to_string(), 1);
1339 let f = send_cloneable_fn_new::<ArcFnBrand, _, _>(|(a, b): (i32, i32)| a + b);
1340 assert_eq!(par_fold_right::<ArcFnBrand, PairWithFirstBrand<String>, _, _>(f, 10, x), 11);
1341 }
1342
1343 // ParFoldable Tests for PairWithSecondBrand (Functor over First)
1344
1345 /// Tests `par_fold_map` on `PairWithSecondBrand`.
1346 #[test]
1347 fn par_fold_map_pair_with_second() {
1348 let x = Pair(1, "a".to_string());
1349 let f = send_cloneable_fn_new::<ArcFnBrand, _, _>(|x: i32| x.to_string());
1350 assert_eq!(
1351 par_fold_map::<ArcFnBrand, PairWithSecondBrand<String>, _, _>(f, x),
1352 "1".to_string()
1353 );
1354 }
1355
1356 /// Tests `par_fold_right` on `PairWithSecondBrand`.
1357 #[test]
1358 fn par_fold_right_pair_with_second() {
1359 let x = Pair(1, "a".to_string());
1360 let f = send_cloneable_fn_new::<ArcFnBrand, _, _>(|(a, b): (i32, i32)| a + b);
1361 assert_eq!(par_fold_right::<ArcFnBrand, PairWithSecondBrand<String>, _, _>(f, 10, x), 11);
1362 }
1363}