fp_library/types/identity.rs
1//! Implementations for [`Identity`], a type that wraps a value.
2
3use crate::{
4 brands::IdentityBrand,
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 semimonad::Semimonad,
17 traversable::Traversable,
18 },
19 hkt::{Apply1L1T, Kind1L1T},
20};
21
22/// Wraps a value.
23#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
24pub struct Identity<A>(pub A);
25
26impl Kind1L1T for IdentityBrand {
27 type Output<'a, A: 'a> = Identity<A>;
28}
29
30impl Functor for IdentityBrand {
31 /// Maps a function over the value in the identity.
32 ///
33 /// # Type Signature
34 ///
35 /// `forall a b. Functor Identity => (a -> b, Identity a) -> Identity b`
36 ///
37 /// # Parameters
38 ///
39 /// * `f`: The function to apply.
40 /// * `fa`: The identity to map over.
41 ///
42 /// # Returns
43 ///
44 /// A new identity containing the result of applying the function.
45 ///
46 /// # Examples
47 ///
48 /// ```
49 /// use fp_library::classes::functor::map;
50 /// use fp_library::brands::IdentityBrand;
51 /// use fp_library::types::Identity;
52 ///
53 /// assert_eq!(map::<IdentityBrand, _, _, _>(|x: i32| x * 2, Identity(5)), Identity(10));
54 /// ```
55 fn map<'a, A: 'a, B: 'a, F>(
56 f: F,
57 fa: Apply1L1T<'a, Self, A>,
58 ) -> Apply1L1T<'a, Self, B>
59 where
60 F: Fn(A) -> B + 'a,
61 {
62 Identity(f(fa.0))
63 }
64}
65
66impl Lift for IdentityBrand {
67 /// Lifts a binary function into the identity context.
68 ///
69 /// # Type Signature
70 ///
71 /// `forall a b c. Lift Identity => ((a, b) -> c, Identity a, Identity b) -> Identity c`
72 ///
73 /// # Parameters
74 ///
75 /// * `f`: The binary function to apply.
76 /// * `fa`: The first identity.
77 /// * `fb`: The second identity.
78 ///
79 /// # Returns
80 ///
81 /// A new identity containing the result of applying the function.
82 ///
83 /// # Examples
84 ///
85 /// ```
86 /// use fp_library::classes::lift::lift2;
87 /// use fp_library::brands::IdentityBrand;
88 /// use fp_library::types::Identity;
89 ///
90 /// assert_eq!(
91 /// lift2::<IdentityBrand, _, _, _, _>(|x: i32, y: i32| x + y, Identity(1), Identity(2)),
92 /// Identity(3)
93 /// );
94 /// ```
95 fn lift2<'a, A, B, C, F>(
96 f: F,
97 fa: Apply1L1T<'a, Self, A>,
98 fb: Apply1L1T<'a, Self, B>,
99 ) -> Apply1L1T<'a, Self, C>
100 where
101 F: Fn(A, B) -> C + 'a,
102 A: 'a,
103 B: 'a,
104 C: 'a,
105 {
106 Identity(f(fa.0, fb.0))
107 }
108}
109
110impl Pointed for IdentityBrand {
111 /// Wraps a value in an identity.
112 ///
113 /// # Type Signature
114 ///
115 /// `forall a. Pointed Identity => a -> Identity a`
116 ///
117 /// # Parameters
118 ///
119 /// * `a`: The value to wrap.
120 ///
121 /// # Returns
122 ///
123 /// An identity containing the value.
124 ///
125 /// # Examples
126 ///
127 /// ```
128 /// use fp_library::classes::pointed::pure;
129 /// use fp_library::brands::IdentityBrand;
130 /// use fp_library::types::Identity;
131 ///
132 /// assert_eq!(pure::<IdentityBrand, _>(5), Identity(5));
133 /// ```
134 fn pure<'a, A: 'a>(a: A) -> Apply1L1T<'a, Self, A> {
135 Identity(a)
136 }
137}
138
139impl ApplyFirst for IdentityBrand {}
140impl ApplySecond for IdentityBrand {}
141
142impl Semiapplicative for IdentityBrand {
143 /// Applies a wrapped function to a wrapped value.
144 ///
145 /// # Type Signature
146 ///
147 /// `forall a b. Semiapplicative Identity => (Identity (a -> b), Identity a) -> Identity b`
148 ///
149 /// # Parameters
150 ///
151 /// * `ff`: The identity containing the function.
152 /// * `fa`: The identity containing the value.
153 ///
154 /// # Returns
155 ///
156 /// A new identity containing the result of applying the function.
157 ///
158 /// # Examples
159 ///
160 /// ```
161 /// use fp_library::classes::semiapplicative::apply;
162 /// use fp_library::classes::clonable_fn::ClonableFn;
163 /// use fp_library::brands::{IdentityBrand};
164 /// use fp_library::types::Identity;
165 /// use fp_library::brands::RcFnBrand;
166 /// use std::rc::Rc;
167 ///
168 /// let f = Identity(<RcFnBrand as ClonableFn>::new(|x: i32| x * 2));
169 /// assert_eq!(apply::<IdentityBrand, _, _, RcFnBrand>(f, Identity(5)), Identity(10));
170 /// ```
171 fn apply<'a, A: 'a + Clone, B: 'a, FnBrand: 'a + ClonableFn>(
172 ff: Apply1L1T<'a, Self, ApplyClonableFn<'a, FnBrand, A, B>>,
173 fa: Apply1L1T<'a, Self, A>,
174 ) -> Apply1L1T<'a, Self, B> {
175 Identity(ff.0(fa.0))
176 }
177}
178
179impl Semimonad for IdentityBrand {
180 /// Chains identity computations.
181 ///
182 /// # Type Signature
183 ///
184 /// `forall a b. Semimonad Identity => (Identity a, a -> Identity b) -> Identity b`
185 ///
186 /// # Parameters
187 ///
188 /// * `ma`: The first identity.
189 /// * `f`: The function to apply to the value inside the identity.
190 ///
191 /// # Returns
192 ///
193 /// The result of applying `f` to the value.
194 ///
195 /// # Examples
196 ///
197 /// ```
198 /// use fp_library::classes::semimonad::bind;
199 /// use fp_library::brands::IdentityBrand;
200 /// use fp_library::types::Identity;
201 ///
202 /// assert_eq!(
203 /// bind::<IdentityBrand, _, _, _>(Identity(5), |x| Identity(x * 2)),
204 /// Identity(10)
205 /// );
206 /// ```
207 fn bind<'a, A: 'a, B: 'a, F>(
208 ma: Apply1L1T<'a, Self, A>,
209 f: F,
210 ) -> Apply1L1T<'a, Self, B>
211 where
212 F: Fn(A) -> Apply1L1T<'a, Self, B> + 'a,
213 {
214 f(ma.0)
215 }
216}
217
218impl Foldable for IdentityBrand {
219 /// Folds the identity from the right.
220 ///
221 /// # Type Signature
222 ///
223 /// `forall a b. Foldable Identity => ((a, b) -> b, b, Identity a) -> b`
224 ///
225 /// # Parameters
226 ///
227 /// * `f`: The folding function.
228 /// * `init`: The initial value.
229 /// * `fa`: The identity to fold.
230 ///
231 /// # Returns
232 ///
233 /// `f(a, init)`.
234 ///
235 /// # Examples
236 ///
237 /// ```
238 /// use fp_library::classes::foldable::fold_right;
239 /// use fp_library::brands::IdentityBrand;
240 /// use fp_library::types::Identity;
241 ///
242 /// assert_eq!(fold_right::<IdentityBrand, _, _, _>(|x: i32, acc| x + acc, 0, Identity(5)), 5);
243 /// ```
244 fn fold_right<'a, A: 'a, B: 'a, F>(
245 f: F,
246 init: B,
247 fa: Apply1L1T<'a, Self, A>,
248 ) -> B
249 where
250 F: Fn(A, B) -> B + 'a,
251 {
252 f(fa.0, init)
253 }
254
255 /// Folds the identity from the left.
256 ///
257 /// # Type Signature
258 ///
259 /// `forall a b. Foldable Identity => ((b, a) -> b, b, Identity a) -> b`
260 ///
261 /// # Parameters
262 ///
263 /// * `f`: The folding function.
264 /// * `init`: The initial value.
265 /// * `fa`: The identity to fold.
266 ///
267 /// # Returns
268 ///
269 /// `f(init, a)`.
270 ///
271 /// # Examples
272 ///
273 /// ```
274 /// use fp_library::classes::foldable::fold_left;
275 /// use fp_library::brands::IdentityBrand;
276 /// use fp_library::types::Identity;
277 ///
278 /// assert_eq!(fold_left::<IdentityBrand, _, _, _>(|acc, x: i32| acc + x, 0, Identity(5)), 5);
279 /// ```
280 fn fold_left<'a, A: 'a, B: 'a, F>(
281 f: F,
282 init: B,
283 fa: Apply1L1T<'a, Self, A>,
284 ) -> B
285 where
286 F: Fn(B, A) -> B + 'a,
287 {
288 f(init, fa.0)
289 }
290
291 /// Maps the value to a monoid and returns it.
292 ///
293 /// # Type Signature
294 ///
295 /// `forall a m. (Foldable Identity, Monoid m) => ((a) -> m, Identity a) -> m`
296 ///
297 /// # Parameters
298 ///
299 /// * `f`: The mapping function.
300 /// * `fa`: The identity to fold.
301 ///
302 /// # Returns
303 ///
304 /// `f(a)`.
305 ///
306 /// # Examples
307 ///
308 /// ```
309 /// use fp_library::classes::foldable::fold_map;
310 /// use fp_library::brands::IdentityBrand;
311 /// use fp_library::types::Identity;
312 /// use fp_library::types::string; // Import to bring Monoid impl for String into scope
313 ///
314 /// assert_eq!(fold_map::<IdentityBrand, _, _, _>(|x: i32| x.to_string(), Identity(5)), "5".to_string());
315 /// ```
316 fn fold_map<'a, A: 'a, M, F>(
317 f: F,
318 fa: Apply1L1T<'a, Self, A>,
319 ) -> M
320 where
321 M: Monoid + 'a,
322 F: Fn(A) -> M + 'a,
323 {
324 f(fa.0)
325 }
326}
327
328impl Traversable for IdentityBrand {
329 /// Traverses the identity with an applicative function.
330 ///
331 /// # Type Signature
332 ///
333 /// `forall a b f. (Traversable Identity, Applicative f) => (a -> f b, Identity a) -> f (Identity b)`
334 ///
335 /// # Parameters
336 ///
337 /// * `f`: The function to apply.
338 /// * `ta`: The identity to traverse.
339 ///
340 /// # Returns
341 ///
342 /// The identity wrapped in the applicative context.
343 ///
344 /// # Examples
345 ///
346 /// ```
347 /// use fp_library::classes::traversable::traverse;
348 /// use fp_library::brands::{IdentityBrand, OptionBrand};
349 /// use fp_library::types::Identity;
350 ///
351 /// assert_eq!(
352 /// traverse::<IdentityBrand, OptionBrand, _, _, _>(|x| Some(x * 2), Identity(5)),
353 /// Some(Identity(10))
354 /// );
355 /// ```
356 fn traverse<'a, F: Applicative, A: 'a + Clone, B: 'a + Clone, Func>(
357 f: Func,
358 ta: Apply1L1T<'a, Self, A>,
359 ) -> Apply1L1T<'a, F, Apply1L1T<'a, Self, B>>
360 where
361 Func: Fn(A) -> Apply1L1T<'a, F, B> + 'a,
362 Apply1L1T<'a, Self, B>: Clone,
363 {
364 F::map(|b| Identity(b), f(ta.0))
365 }
366
367 /// Sequences an identity of applicative.
368 ///
369 /// # Type Signature
370 ///
371 /// `forall a f. (Traversable Identity, Applicative f) => (Identity (f a)) -> f (Identity a)`
372 ///
373 /// # Parameters
374 ///
375 /// * `ta`: The identity containing the applicative value.
376 ///
377 /// # Returns
378 ///
379 /// The identity wrapped in the applicative context.
380 ///
381 /// # Examples
382 ///
383 /// ```
384 /// use fp_library::classes::traversable::sequence;
385 /// use fp_library::brands::{IdentityBrand, OptionBrand};
386 /// use fp_library::types::Identity;
387 ///
388 /// assert_eq!(
389 /// sequence::<IdentityBrand, OptionBrand, _>(Identity(Some(5))),
390 /// Some(Identity(5))
391 /// );
392 /// ```
393 fn sequence<'a, F: Applicative, A: 'a + Clone>(
394 ta: Apply1L1T<'a, Self, Apply1L1T<'a, F, A>>
395 ) -> Apply1L1T<'a, F, Apply1L1T<'a, Self, A>>
396 where
397 Apply1L1T<'a, F, A>: Clone,
398 Apply1L1T<'a, Self, A>: Clone,
399 {
400 F::map(|a| Identity(a), ta.0)
401 }
402}
403
404#[cfg(test)]
405mod tests {
406 use super::*;
407 use crate::{
408 brands::{OptionBrand, RcFnBrand},
409 classes::{functor::map, pointed::pure, semiapplicative::apply, semimonad::bind},
410 functions::{compose, identity},
411 };
412 use quickcheck_macros::quickcheck;
413
414 // Functor Laws
415
416 /// Tests the identity law for Functor.
417 #[quickcheck]
418 fn functor_identity(x: i32) -> bool {
419 let x = Identity(x);
420 map::<IdentityBrand, _, _, _>(identity, x) == x
421 }
422
423 /// Tests the composition law for Functor.
424 #[quickcheck]
425 fn functor_composition(x: i32) -> bool {
426 let x = Identity(x);
427 let f = |x: i32| x.wrapping_add(1);
428 let g = |x: i32| x.wrapping_mul(2);
429 map::<IdentityBrand, _, _, _>(compose(f, g), x)
430 == map::<IdentityBrand, _, _, _>(f, map::<IdentityBrand, _, _, _>(g, x))
431 }
432
433 // Applicative Laws
434
435 /// Tests the identity law for Applicative.
436 #[quickcheck]
437 fn applicative_identity(v: i32) -> bool {
438 let v = Identity(v);
439 apply::<IdentityBrand, _, _, RcFnBrand>(
440 pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(identity)),
441 v,
442 ) == v
443 }
444
445 /// Tests the homomorphism law for Applicative.
446 #[quickcheck]
447 fn applicative_homomorphism(x: i32) -> bool {
448 let f = |x: i32| x.wrapping_mul(2);
449 apply::<IdentityBrand, _, _, RcFnBrand>(
450 pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(f)),
451 pure::<IdentityBrand, _>(x),
452 ) == pure::<IdentityBrand, _>(f(x))
453 }
454
455 /// Tests the composition law for Applicative.
456 #[quickcheck]
457 fn applicative_composition(
458 w: i32,
459 u_val: i32,
460 v_val: i32,
461 ) -> bool {
462 let w = Identity(w);
463 let v_fn = move |x: i32| x.wrapping_mul(v_val);
464 let u_fn = move |x: i32| x.wrapping_add(u_val);
465
466 let v = pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(v_fn));
467 let u = pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(u_fn));
468
469 // RHS: u <*> (v <*> w)
470 let vw = apply::<IdentityBrand, _, _, RcFnBrand>(v.clone(), w.clone());
471 let rhs = apply::<IdentityBrand, _, _, RcFnBrand>(u.clone(), vw);
472
473 // LHS: pure(compose) <*> u <*> v <*> w
474 // equivalent to (u . v) <*> w
475 let composed = move |x| u_fn(v_fn(x));
476 let uv = pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(composed));
477
478 let lhs = apply::<IdentityBrand, _, _, RcFnBrand>(uv, w);
479
480 lhs == rhs
481 }
482
483 /// Tests the interchange law for Applicative.
484 #[quickcheck]
485 fn applicative_interchange(y: i32) -> bool {
486 // u <*> pure y = pure ($ y) <*> u
487 let f = |x: i32| x.wrapping_mul(2);
488 let u = pure::<IdentityBrand, _>(<RcFnBrand as ClonableFn>::new(f));
489
490 let lhs = apply::<IdentityBrand, _, _, RcFnBrand>(u.clone(), pure::<IdentityBrand, _>(y));
491
492 let rhs_fn = <RcFnBrand as ClonableFn>::new(move |f: std::rc::Rc<dyn Fn(i32) -> i32>| f(y));
493 let rhs = apply::<IdentityBrand, _, _, RcFnBrand>(pure::<IdentityBrand, _>(rhs_fn), u);
494
495 lhs == rhs
496 }
497
498 // Monad Laws
499
500 /// Tests the left identity law for Monad.
501 #[quickcheck]
502 fn monad_left_identity(a: i32) -> bool {
503 let f = |x: i32| Identity(x.wrapping_mul(2));
504 bind::<IdentityBrand, _, _, _>(pure::<IdentityBrand, _>(a), f) == f(a)
505 }
506
507 /// Tests the right identity law for Monad.
508 #[quickcheck]
509 fn monad_right_identity(m: i32) -> bool {
510 let m = Identity(m);
511 bind::<IdentityBrand, _, _, _>(m, pure::<IdentityBrand, _>) == m
512 }
513
514 /// Tests the associativity law for Monad.
515 #[quickcheck]
516 fn monad_associativity(m: i32) -> bool {
517 let m = Identity(m);
518 let f = |x: i32| Identity(x.wrapping_mul(2));
519 let g = |x: i32| Identity(x.wrapping_add(1));
520 bind::<IdentityBrand, _, _, _>(bind::<IdentityBrand, _, _, _>(m, f), g)
521 == bind::<IdentityBrand, _, _, _>(m, |x| bind::<IdentityBrand, _, _, _>(f(x), g))
522 }
523
524 // Edge Cases
525
526 /// Tests the `map` function.
527 #[test]
528 fn map_test() {
529 assert_eq!(map::<IdentityBrand, _, _, _>(|x: i32| x + 1, Identity(1)), Identity(2));
530 }
531
532 /// Tests the `bind` function.
533 #[test]
534 fn bind_test() {
535 assert_eq!(bind::<IdentityBrand, _, _, _>(Identity(1), |x| Identity(x + 1)), Identity(2));
536 }
537
538 /// Tests the `fold_right` function.
539 #[test]
540 fn fold_right_test() {
541 assert_eq!(
542 crate::classes::foldable::fold_right::<IdentityBrand, _, _, _>(
543 |x: i32, acc| x + acc,
544 0,
545 Identity(1)
546 ),
547 1
548 );
549 }
550
551 /// Tests the `fold_left` function.
552 #[test]
553 fn fold_left_test() {
554 assert_eq!(
555 crate::classes::foldable::fold_left::<IdentityBrand, _, _, _>(
556 |acc, x: i32| acc + x,
557 0,
558 Identity(1)
559 ),
560 1
561 );
562 }
563
564 /// Tests the `traverse` function.
565 #[test]
566 fn traverse_test() {
567 assert_eq!(
568 crate::classes::traversable::traverse::<IdentityBrand, OptionBrand, _, _, _>(
569 |x: i32| Some(x + 1),
570 Identity(1)
571 ),
572 Some(Identity(2))
573 );
574 }
575}