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