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