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