fp_library/types/identity.rs
1//! Implementations for [`Identity`], a type that wraps a value.
2//!
3//! This module provides implementations of functional programming traits for the [`Identity`] type.
4
5use crate::{
6 Apply,
7 brands::IdentityBrand,
8 classes::{
9 applicative::Applicative, apply_first::ApplyFirst, apply_second::ApplySecond,
10 clonable_fn::ClonableFn, foldable::Foldable, functor::Functor, lift::Lift, monoid::Monoid,
11 par_foldable::ParFoldable, pointed::Pointed, semiapplicative::Semiapplicative,
12 semimonad::Semimonad, send_clonable_fn::SendClonableFn, traversable::Traversable,
13 },
14 impl_kind,
15 kinds::*,
16};
17
18/// Wraps a value.
19///
20/// The `Identity` type represents a trivial wrapper around a value. It is the simplest possible container.
21/// It is often used as a base case for higher-kinded types or when a container is required but no additional effect is needed.
22#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
23pub struct Identity<A>(pub A);
24
25impl_kind! {
26 for IdentityBrand {
27 type Of<'a, A: 'a>: 'a = Identity<A>;
28 }
29}
30
31impl Functor for IdentityBrand {
32 /// Maps a function over the value in the identity.
33 ///
34 /// This method applies a function to the value inside the identity, producing a new identity with the transformed value.
35 ///
36 /// ### Type Signature
37 ///
38 /// `forall a b. Functor Identity => (a -> b, Identity a) -> Identity b`
39 ///
40 /// ### Parameters
41 ///
42 /// * `f`: The function to apply.
43 /// * `fa`: The identity to map over.
44 ///
45 /// ### Returns
46 ///
47 /// A new identity containing the result of applying the function.
48 ///
49 /// ### Examples
50 ///
51 /// ```
52 /// use fp_library::classes::functor::Functor;
53 /// use fp_library::brands::IdentityBrand;
54 /// use fp_library::types::Identity;
55 ///
56 /// let x = Identity(5);
57 /// let y = IdentityBrand::map(|i| i * 2, x);
58 /// assert_eq!(y, Identity(10));
59 ///
60 /// // Using the free function
61 /// use fp_library::classes::functor::map;
62 /// assert_eq!(map::<IdentityBrand, _, _, _>(|x: i32| x * 2, Identity(5)), Identity(10));
63 /// ```
64 fn map<'a, F, A: 'a, B: 'a>(
65 f: F,
66 fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
67 ) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a)
68 where
69 F: Fn(A) -> B + 'a,
70 {
71 Identity(f(fa.0))
72 }
73}
74
75impl Lift for IdentityBrand {
76 /// Lifts a binary function into the identity context.
77 ///
78 /// This method lifts a binary function to operate on values within the identity context.
79 ///
80 /// ### Type Signature
81 ///
82 /// `forall a b c. Lift Identity => ((a, b) -> c, Identity a, Identity b) -> Identity c`
83 ///
84 /// ### Parameters
85 ///
86 /// * `f`: The binary function to apply.
87 /// * `fa`: The first identity.
88 /// * `fb`: The second identity.
89 ///
90 /// ### Returns
91 ///
92 /// A new identity containing the result of applying the function.
93 ///
94 /// ### Examples
95 ///
96 /// ```
97 /// use fp_library::classes::lift::Lift;
98 /// use fp_library::brands::IdentityBrand;
99 /// use fp_library::types::Identity;
100 ///
101 /// let x = Identity(1);
102 /// let y = Identity(2);
103 /// let z = IdentityBrand::lift2(|a, b| a + b, x, y);
104 /// assert_eq!(z, Identity(3));
105 ///
106 /// // Using the free function
107 /// use fp_library::classes::lift::lift2;
108 /// assert_eq!(
109 /// lift2::<IdentityBrand, _, _, _, _>(|x: i32, y: i32| x + y, Identity(1), Identity(2)),
110 /// Identity(3)
111 /// );
112 /// ```
113 fn lift2<'a, F, A, B, C>(
114 f: F,
115 fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
116 fb: Apply!(brand: Self, signature: ('a, B: 'a) -> 'a),
117 ) -> Apply!(brand: Self, signature: ('a, C: 'a) -> 'a)
118 where
119 F: Fn(A, B) -> C + 'a,
120 A: 'a,
121 B: 'a,
122 C: 'a,
123 {
124 Identity(f(fa.0, fb.0))
125 }
126}
127
128impl Pointed for IdentityBrand {
129 /// Wraps a value in an identity.
130 ///
131 /// This method wraps a value in an identity context.
132 ///
133 /// ### Type Signature
134 ///
135 /// `forall a. Pointed Identity => a -> Identity a`
136 ///
137 /// ### Parameters
138 ///
139 /// * `a`: The value to wrap.
140 ///
141 /// ### Returns
142 ///
143 /// An identity containing the value.
144 ///
145 /// ### Examples
146 ///
147 /// ```
148 /// use fp_library::classes::pointed::Pointed;
149 /// use fp_library::brands::IdentityBrand;
150 /// use fp_library::types::Identity;
151 ///
152 /// let x = IdentityBrand::pure(5);
153 /// assert_eq!(x, Identity(5));
154 ///
155 /// // Using the free function
156 /// use fp_library::classes::pointed::pure;
157 /// assert_eq!(pure::<IdentityBrand, _>(5), Identity(5));
158 /// ```
159 fn pure<'a, A: 'a>(a: A) -> Apply!(brand: Self, signature: ('a, A: 'a) -> 'a) {
160 Identity(a)
161 }
162}
163
164impl ApplyFirst for IdentityBrand {}
165impl ApplySecond for IdentityBrand {}
166
167impl Semiapplicative for IdentityBrand {
168 /// Applies a wrapped function to a wrapped value.
169 ///
170 /// This method applies a function wrapped in an identity to a value wrapped in an identity.
171 ///
172 /// ### Type Signature
173 ///
174 /// `forall a b. Semiapplicative Identity => (Identity (a -> b), Identity a) -> Identity b`
175 ///
176 /// ### Parameters
177 ///
178 /// * `ff`: The identity containing the function.
179 /// * `fa`: The identity containing the value.
180 ///
181 /// ### Returns
182 ///
183 /// A new identity containing the result of applying the function.
184 ///
185 /// ### Examples
186 ///
187 /// ```
188 /// use fp_library::classes::semiapplicative::Semiapplicative;
189 /// use fp_library::classes::clonable_fn::ClonableFn;
190 /// use fp_library::brands::{IdentityBrand};
191 /// use fp_library::types::Identity;
192 /// use fp_library::brands::RcFnBrand;
193 /// use std::rc::Rc;
194 ///
195 /// let f = Identity(<RcFnBrand as ClonableFn>::new(|x: i32| x * 2));
196 /// let x = Identity(5);
197 /// let y = IdentityBrand::apply::<RcFnBrand, i32, i32>(f, x);
198 /// assert_eq!(y, Identity(10));
199 ///
200 /// // Using the free function
201 /// use fp_library::classes::semiapplicative::apply;
202 /// let f = Identity(<RcFnBrand as ClonableFn>::new(|x: i32| x * 2));
203 /// assert_eq!(apply::<RcFnBrand, IdentityBrand, _, _>(f, Identity(5)), Identity(10));
204 /// ```
205 fn apply<'a, FnBrand: 'a + ClonableFn, A: 'a + Clone, B: 'a>(
206 ff: Apply!(brand: Self, signature: ('a, Apply!(brand: FnBrand, kind: ClonableFn, lifetimes: ('a), types: (A, B)): 'a) -> 'a),
207 fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
208 ) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a) {
209 Identity(ff.0(fa.0))
210 }
211}
212
213impl Semimonad for IdentityBrand {
214 /// Chains identity computations.
215 ///
216 /// This method chains two identity computations, where the second computation depends on the result of the first.
217 ///
218 /// ### Type Signature
219 ///
220 /// `forall a b. Semimonad Identity => (Identity a, a -> Identity b) -> Identity b`
221 ///
222 /// ### Parameters
223 ///
224 /// * `ma`: The first identity.
225 /// * `f`: The function to apply to the value inside the identity.
226 ///
227 /// ### Returns
228 ///
229 /// The result of applying `f` to the value.
230 ///
231 /// ### Examples
232 ///
233 /// ```
234 /// use fp_library::classes::semimonad::Semimonad;
235 /// use fp_library::brands::IdentityBrand;
236 /// use fp_library::types::Identity;
237 ///
238 /// let x = Identity(5);
239 /// let y = IdentityBrand::bind(x, |i| Identity(i * 2));
240 /// assert_eq!(y, Identity(10));
241 ///
242 /// // Using the free function
243 /// use fp_library::classes::semimonad::bind;
244 /// assert_eq!(
245 /// bind::<IdentityBrand, _, _, _>(Identity(5), |x| Identity(x * 2)),
246 /// Identity(10)
247 /// );
248 /// ```
249 fn bind<'a, F, A: 'a, B: 'a>(
250 ma: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
251 f: F,
252 ) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a)
253 where
254 F: Fn(A) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a) + 'a,
255 {
256 f(ma.0)
257 }
258}
259
260impl Foldable for IdentityBrand {
261 /// Folds the identity from the right.
262 ///
263 /// This method performs a right-associative fold of the identity. Since `Identity` contains only one element, this is equivalent to applying the function to the element and the initial value.
264 ///
265 /// ### Type Signature
266 ///
267 /// `forall a b. Foldable Identity => ((a, b) -> b, b, Identity a) -> b`
268 /// ### Parameters
269 ///
270 /// * `func`: The function to apply to each element and the accumulator.
271 /// * `initial`: The initial value of the accumulator.
272 /// * `fa`: The identity to fold.
273 ///
274 /// ### Returns
275 ///
276 /// The final accumulator value.
277 ///
278 /// ### Examples
279 ///
280 /// ```
281 /// use fp_library::classes::foldable::Foldable;
282 /// use fp_library::brands::IdentityBrand;
283 /// use fp_library::types::Identity;
284 /// use fp_library::brands::RcFnBrand;
285 ///
286 /// let x = Identity(5);
287 /// let y = IdentityBrand::fold_right::<RcFnBrand, _, _, _>(|a, b| a + b, 10, x);
288 /// assert_eq!(y, 15);
289 ///
290 /// // Using the free function
291 /// use fp_library::classes::foldable::fold_right;
292 /// assert_eq!(fold_right::<RcFnBrand, IdentityBrand, _, _, _>(|x: i32, acc| x + acc, 0, Identity(5)), 5);
293 /// ```
294 fn fold_right<'a, FnBrand, Func, A: 'a, B: 'a>(
295 func: Func,
296 initial: B,
297 fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
298 ) -> B
299 where
300 Func: Fn(A, B) -> B + 'a,
301 FnBrand: ClonableFn + 'a,
302 {
303 func(fa.0, initial)
304 }
305
306 /// Folds the identity from the left.
307 ///
308 /// This method performs a left-associative fold of the identity. Since `Identity` contains only one element, this is equivalent to applying the function to the initial value and the element.
309 ///
310 /// ### Type Signature
311 ///
312 /// `forall a b. Foldable Identity => ((b, a) -> b, b, Identity a) -> b`
313 ///
314 /// ### Parameters
315 ///
316 /// * `func`: The function to apply to the accumulator and each element.
317 /// * `initial`: The initial value of the accumulator.
318 /// * `fa`: The identity to fold.
319 ///
320 /// ### Returns
321 ///
322 /// The final accumulator value.
323 ///
324 /// ### Examples
325 ///
326 /// ```
327 /// use fp_library::classes::foldable::Foldable;
328 /// use fp_library::brands::IdentityBrand;
329 /// use fp_library::types::Identity;
330 /// use fp_library::brands::RcFnBrand;
331 ///
332 /// let x = Identity(5);
333 /// let y = IdentityBrand::fold_left::<RcFnBrand, _, _, _>(|b, a| b + a, 10, x);
334 /// assert_eq!(y, 15);
335 ///
336 /// // Using the free function
337 /// use fp_library::classes::foldable::fold_left;
338 /// assert_eq!(fold_left::<RcFnBrand, IdentityBrand, _, _, _>(|acc, x: i32| acc + x, 0, Identity(5)), 5);
339 /// ```
340 fn fold_left<'a, FnBrand, Func, A: 'a, B: 'a>(
341 func: Func,
342 initial: B,
343 fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
344 ) -> B
345 where
346 Func: Fn(B, A) -> B + 'a,
347 FnBrand: ClonableFn + 'a,
348 {
349 func(initial, fa.0)
350 }
351
352 /// Maps the value to a monoid and returns it.
353 ///
354 /// This method maps the element of the identity to a monoid.
355 ///
356 /// ### Type Signature
357 ///
358 /// `forall a m. (Foldable Identity, Monoid m) => ((a) -> m, Identity a) -> m`
359 ///
360 /// ### Parameters
361 ///
362 /// * `func`: The mapping function.
363 /// * `fa`: The identity to fold.
364 ///
365 /// ### Returns
366 ///
367 /// The monoid value.
368 ///
369 /// ### Examples
370 ///
371 /// ```
372 /// use fp_library::classes::foldable::Foldable;
373 /// use fp_library::brands::IdentityBrand;
374 /// use fp_library::types::Identity;
375 /// use fp_library::types::string; // Import to bring Monoid impl for String into scope
376 /// use fp_library::brands::RcFnBrand;
377 ///
378 /// let x = Identity(5);
379 /// let y = IdentityBrand::fold_map::<RcFnBrand, _, _, _>(|a: i32| a.to_string(), x);
380 /// assert_eq!(y, "5".to_string());
381 ///
382 /// // Using the free function
383 /// use fp_library::classes::foldable::fold_map;
384 /// assert_eq!(fold_map::<RcFnBrand, IdentityBrand, _, _, _>(|x: i32| x.to_string(), Identity(5)), "5".to_string());
385 /// ```
386 fn fold_map<'a, FnBrand, Func, A: 'a, M>(
387 func: Func,
388 fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
389 ) -> M
390 where
391 M: Monoid + 'a,
392 Func: Fn(A) -> M + 'a,
393 FnBrand: ClonableFn + 'a,
394 {
395 func(fa.0)
396 }
397}
398
399impl Traversable for IdentityBrand {
400 /// Traverses the identity with an applicative function.
401 ///
402 /// This method maps the element of the identity to a computation, evaluates it, and wraps the result in the applicative context.
403 ///
404 /// ### Type Signature
405 ///
406 /// `forall a b f. (Traversable Identity, Applicative f) => (a -> f b, Identity a) -> f (Identity b)`
407 ///
408 /// ### Parameters
409 ///
410 /// * `func`: The function to apply to each element, returning a value in an applicative context.
411 /// * `ta`: The identity to traverse.
412 ///
413 /// ### Returns
414 ///
415 /// The identity wrapped in the applicative context.
416 ///
417 /// ### Examples
418 ///
419 /// ```
420 /// use fp_library::classes::traversable::Traversable;
421 /// use fp_library::brands::{IdentityBrand, OptionBrand};
422 /// use fp_library::types::Identity;
423 ///
424 /// let x = Identity(5);
425 /// let y = IdentityBrand::traverse::<OptionBrand, _, _, _>(|a| Some(a * 2), x);
426 /// assert_eq!(y, Some(Identity(10)));
427 ///
428 /// // Using the free function
429 /// use fp_library::classes::traversable::traverse;
430 /// assert_eq!(
431 /// traverse::<IdentityBrand, OptionBrand, _, _, _>(|x| Some(x * 2), Identity(5)),
432 /// Some(Identity(10))
433 /// );
434 /// ```
435 fn traverse<'a, F: Applicative, Func, A: 'a + Clone, B: 'a + Clone>(
436 func: Func,
437 ta: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
438 ) -> Apply!(brand: F, signature: ('a, Apply!(brand: Self, signature: ('a, B: 'a) -> 'a): 'a) -> 'a)
439 where
440 Func: Fn(A) -> Apply!(brand: F, signature: ('a, B: 'a) -> 'a) + 'a,
441 Apply!(brand: Self, signature: ('a, B: 'a) -> 'a): Clone,
442 {
443 F::map(|b| Identity(b), func(ta.0))
444 }
445
446 /// Sequences an identity of applicative.
447 ///
448 /// This method evaluates the computation inside the identity and wraps the result in the applicative context.
449 ///
450 /// ### Type Signature
451 ///
452 /// `forall a f. (Traversable Identity, Applicative f) => (Identity (f a)) -> f (Identity a)`
453 ///
454 /// ### Parameters
455 ///
456 /// * `ta`: The identity containing the applicative value.
457 ///
458 /// ### Returns
459 ///
460 /// The identity wrapped in the applicative context.
461 ///
462 /// ### Examples
463 ///
464 /// ```
465 /// use fp_library::classes::traversable::Traversable;
466 /// use fp_library::brands::{IdentityBrand, OptionBrand};
467 /// use fp_library::types::Identity;
468 ///
469 /// let x = Identity(Some(5));
470 /// let y = IdentityBrand::sequence::<OptionBrand, _>(x);
471 /// assert_eq!(y, Some(Identity(5)));
472 ///
473 /// // Using the free function
474 /// use fp_library::classes::traversable::sequence;
475 /// assert_eq!(
476 /// sequence::<IdentityBrand, OptionBrand, _>(Identity(Some(5))),
477 /// Some(Identity(5))
478 /// );
479 /// ```
480 fn sequence<'a, F: Applicative, A: 'a + Clone>(
481 ta: Apply!(brand: Self, signature: ('a, Apply!(brand: F, signature: ('a, A: 'a) -> 'a): 'a) -> 'a)
482 ) -> Apply!(brand: F, signature: ('a, Apply!(brand: Self, signature: ('a, A: 'a) -> 'a): 'a) -> 'a)
483 where
484 Apply!(brand: F, signature: ('a, A: 'a) -> 'a): Clone,
485 Apply!(brand: Self, signature: ('a, A: 'a) -> 'a): Clone,
486 {
487 F::map(|a| Identity(a), ta.0)
488 }
489}
490
491impl<FnBrand: SendClonableFn> ParFoldable<FnBrand> for IdentityBrand {
492 /// Maps the value to a monoid and returns it in parallel.
493 ///
494 /// This method maps the element of the identity to a monoid. Since `Identity` contains only one element, no actual parallelism occurs, but the interface is satisfied.
495 ///
496 /// ### Type Signature
497 ///
498 /// `forall a m. (ParFoldable Identity, Monoid m, Send m, Sync m) => (f a m, Identity a) -> m`
499 ///
500 /// ### Parameters
501 ///
502 /// * `func`: The mapping function.
503 /// * `fa`: The identity to fold.
504 ///
505 /// ### Returns
506 ///
507 /// The combined monoid value.
508 ///
509 /// ### Examples
510 ///
511 /// ```
512 /// use fp_library::classes::par_foldable::ParFoldable;
513 /// use fp_library::brands::{IdentityBrand, ArcFnBrand};
514 /// use fp_library::types::Identity;
515 /// use fp_library::classes::send_clonable_fn::SendClonableFn;
516 /// use fp_library::classes::send_clonable_fn::new_send;
517 ///
518 /// let x = Identity(1);
519 /// let f = new_send::<ArcFnBrand, _, _>(|x: i32| x.to_string());
520 /// let y = <IdentityBrand as ParFoldable<ArcFnBrand>>::par_fold_map(f, x);
521 /// assert_eq!(y, "1".to_string());
522 ///
523 /// // Using the free function
524 /// use fp_library::classes::par_foldable::par_fold_map;
525 /// let x = Identity(1);
526 /// let f = new_send::<ArcFnBrand, _, _>(|x: i32| x.to_string());
527 /// assert_eq!(par_fold_map::<ArcFnBrand, IdentityBrand, _, _>(f, x), "1".to_string());
528 /// ```
529 fn par_fold_map<'a, A, M>(
530 func: Apply!(brand: FnBrand, kind: SendClonableFn, output: SendOf, lifetimes: ('a), types: (A, M)),
531 fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
532 ) -> M
533 where
534 A: 'a + Clone + Send + Sync,
535 M: Monoid + Send + Sync + 'a,
536 {
537 func(fa.0)
538 }
539
540 /// Folds the identity from the right in parallel.
541 ///
542 /// This method performs a right-associative fold of the identity. Since `Identity` contains only one element, no actual parallelism occurs.
543 ///
544 /// ### Type Signature
545 ///
546 /// `forall a b. ParFoldable Identity => (f (a, b) b, b, Identity a) -> b`
547 /// ### Parameters
548 ///
549 /// * `func`: The thread-safe function to apply to each element and the accumulator.
550 /// * `initial`: The initial value of the accumulator.
551 /// * `fa`: The identity to fold.
552 ///
553 /// ### Returns
554 ///
555 /// The final accumulator value.
556 ///
557 /// ### Examples
558 ///
559 /// ```
560 /// use fp_library::classes::par_foldable::ParFoldable;
561 /// use fp_library::brands::{IdentityBrand, ArcFnBrand};
562 /// use fp_library::types::Identity;
563 /// use fp_library::classes::send_clonable_fn::SendClonableFn;
564 /// use fp_library::classes::send_clonable_fn::new_send;
565 ///
566 /// let x = Identity(1);
567 /// let f = new_send::<ArcFnBrand, _, _>(|(a, b): (i32, i32)| a + b);
568 /// let y = <IdentityBrand as ParFoldable<ArcFnBrand>>::par_fold_right(f, 10, x);
569 /// assert_eq!(y, 11);
570 ///
571 /// // Using the free function
572 /// use fp_library::classes::par_foldable::par_fold_right;
573 /// let x = Identity(1);
574 /// let f = new_send::<ArcFnBrand, _, _>(|(a, b): (i32, i32)| a + b);
575 /// assert_eq!(par_fold_right::<ArcFnBrand, IdentityBrand, _, _>(f, 10, x), 11);
576 /// ```
577 fn par_fold_right<'a, A, B>(
578 func: Apply!(brand: FnBrand, kind: SendClonableFn, output: SendOf, lifetimes: ('a), types: ((A, B), B)),
579 initial: B,
580 fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
581 ) -> B
582 where
583 A: 'a + Clone + Send + Sync,
584 B: Send + Sync + 'a,
585 {
586 func((fa.0, initial))
587 }
588}
589
590#[cfg(test)]
591mod tests {
592 use super::*;
593 use crate::{
594 brands::{OptionBrand, RcFnBrand},
595 classes::{functor::map, pointed::pure, semiapplicative::apply, semimonad::bind},
596 functions::{compose, identity},
597 };
598 use quickcheck_macros::quickcheck;
599
600 // Functor Laws
601
602 /// Tests the identity law for Functor.
603 #[quickcheck]
604 fn functor_identity(x: i32) -> bool {
605 let x = Identity(x);
606 map::<IdentityBrand, _, _, _>(identity, x) == x
607 }
608
609 /// Tests the composition law for Functor.
610 #[quickcheck]
611 fn functor_composition(x: i32) -> bool {
612 let x = Identity(x);
613 let f = |x: i32| x.wrapping_add(1);
614 let g = |x: i32| x.wrapping_mul(2);
615 map::<IdentityBrand, _, _, _>(compose(f, g), x)
616 == map::<IdentityBrand, _, _, _>(f, map::<IdentityBrand, _, _, _>(g, x))
617 }
618
619 // Applicative Laws
620
621 /// Tests the identity law for Applicative.
622 #[quickcheck]
623 fn applicative_identity(v: i32) -> bool {
624 let v = Identity(v);
625 apply::<RcFnBrand, IdentityBrand, _, _>(
626 pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(identity)),
627 v,
628 ) == v
629 }
630
631 /// Tests the homomorphism law for Applicative.
632 #[quickcheck]
633 fn applicative_homomorphism(x: i32) -> bool {
634 let f = |x: i32| x.wrapping_mul(2);
635 apply::<RcFnBrand, IdentityBrand, _, _>(
636 pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(f)),
637 pure::<IdentityBrand, _>(x),
638 ) == pure::<IdentityBrand, _>(f(x))
639 }
640
641 /// Tests the composition law for Applicative.
642 #[quickcheck]
643 fn applicative_composition(
644 w: i32,
645 u_val: i32,
646 v_val: i32,
647 ) -> bool {
648 let w = Identity(w);
649 let v_fn = move |x: i32| x.wrapping_mul(v_val);
650 let u_fn = move |x: i32| x.wrapping_add(u_val);
651
652 let v = pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(v_fn));
653 let u = pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(u_fn));
654
655 // RHS: u <*> (v <*> w)
656 let vw = apply::<RcFnBrand, IdentityBrand, _, _>(v.clone(), w.clone());
657 let rhs = apply::<RcFnBrand, IdentityBrand, _, _>(u.clone(), vw);
658
659 // LHS: pure(compose) <*> u <*> v <*> w
660 // equivalent to (u . v) <*> w
661 let composed = move |x| u_fn(v_fn(x));
662 let uv = pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(composed));
663
664 let lhs = apply::<RcFnBrand, IdentityBrand, _, _>(uv, w);
665
666 lhs == rhs
667 }
668
669 /// Tests the interchange law for Applicative.
670 #[quickcheck]
671 fn applicative_interchange(y: i32) -> bool {
672 // u <*> pure y = pure ($ y) <*> u
673 let f = |x: i32| x.wrapping_mul(2);
674 let u = pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(f));
675
676 let lhs = apply::<RcFnBrand, IdentityBrand, _, _>(u.clone(), pure::<IdentityBrand, _>(y));
677
678 let rhs_fn = <RcFnBrand as ClonableFn>::new(move |f: std::rc::Rc<dyn Fn(i32) -> i32>| f(y));
679 let rhs = apply::<RcFnBrand, IdentityBrand, _, _>(pure::<IdentityBrand, _>(rhs_fn), u);
680
681 lhs == rhs
682 }
683
684 // Monad Laws
685
686 /// Tests the left identity law for Monad.
687 #[quickcheck]
688 fn monad_left_identity(a: i32) -> bool {
689 let f = |x: i32| Identity(x.wrapping_mul(2));
690 bind::<IdentityBrand, _, _, _>(pure::<IdentityBrand, _>(a), f) == f(a)
691 }
692
693 /// Tests the right identity law for Monad.
694 #[quickcheck]
695 fn monad_right_identity(m: i32) -> bool {
696 let m = Identity(m);
697 bind::<IdentityBrand, _, _, _>(m, pure::<IdentityBrand, _>) == m
698 }
699
700 /// Tests the associativity law for Monad.
701 #[quickcheck]
702 fn monad_associativity(m: i32) -> bool {
703 let m = Identity(m);
704 let f = |x: i32| Identity(x.wrapping_mul(2));
705 let g = |x: i32| Identity(x.wrapping_add(1));
706 bind::<IdentityBrand, _, _, _>(bind::<IdentityBrand, _, _, _>(m, f), g)
707 == bind::<IdentityBrand, _, _, _>(m, |x| bind::<IdentityBrand, _, _, _>(f(x), g))
708 }
709
710 // Edge Cases
711
712 /// Tests the `map` function.
713 #[test]
714 fn map_test() {
715 assert_eq!(map::<IdentityBrand, _, _, _>(|x: i32| x + 1, Identity(1)), Identity(2));
716 }
717
718 /// Tests the `bind` function.
719 #[test]
720 fn bind_test() {
721 assert_eq!(bind::<IdentityBrand, _, _, _>(Identity(1), |x| Identity(x + 1)), Identity(2));
722 }
723
724 /// Tests the `fold_right` function.
725 #[test]
726 fn fold_right_test() {
727 assert_eq!(
728 crate::classes::foldable::fold_right::<RcFnBrand, IdentityBrand, _, _, _>(
729 |x: i32, acc| x + acc,
730 0,
731 Identity(1)
732 ),
733 1
734 );
735 }
736
737 /// Tests the `fold_left` function.
738 #[test]
739 fn fold_left_test() {
740 assert_eq!(
741 crate::classes::foldable::fold_left::<RcFnBrand, IdentityBrand, _, _, _>(
742 |acc, x: i32| acc + x,
743 0,
744 Identity(1)
745 ),
746 1
747 );
748 }
749
750 /// Tests the `traverse` function.
751 #[test]
752 fn traverse_test() {
753 assert_eq!(
754 crate::classes::traversable::traverse::<IdentityBrand, OptionBrand, _, _, _>(
755 |x: i32| Some(x + 1),
756 Identity(1)
757 ),
758 Some(Identity(2))
759 );
760 }
761
762 // ParFoldable Tests
763
764 /// Tests `par_fold_map`.
765 #[test]
766 fn par_fold_map_test() {
767 use crate::brands::ArcFnBrand;
768 use crate::classes::par_foldable::par_fold_map;
769 use crate::classes::send_clonable_fn::new_send;
770
771 let x = Identity(1);
772 let f = new_send::<ArcFnBrand, _, _>(|x: i32| x.to_string());
773 assert_eq!(par_fold_map::<ArcFnBrand, IdentityBrand, _, _>(f, x), "1".to_string());
774 }
775
776 /// Tests `par_fold_right`.
777 #[test]
778 fn par_fold_right_test() {
779 use crate::brands::ArcFnBrand;
780 use crate::classes::par_foldable::par_fold_right;
781 use crate::classes::send_clonable_fn::new_send;
782
783 let x = Identity(1);
784 let f = new_send::<ArcFnBrand, _, _>(|(a, b): (i32, i32)| a + b);
785 assert_eq!(par_fold_right::<ArcFnBrand, IdentityBrand, _, _>(f, 10, x), 11);
786 }
787}