fp_library/classes/monoid.rs
1//! Types that have an identity element and an associative binary operation.
2//!
3//! ### Examples
4//!
5//! ```
6//! use fp_library::functions::*;
7//!
8//! let x: String = empty();
9//! assert_eq!(x, "".to_string());
10//! ```
11
12#[fp_macros::document_module]
13mod inner {
14 use {
15 crate::classes::*,
16 fp_macros::*,
17 };
18
19 /// A type class for types that have an identity element and an associative binary operation.
20 ///
21 /// ### Laws
22 ///
23 /// `Monoid` instances must satisfy the identity laws:
24 /// * Left Identity: `append(empty(), a) = a`.
25 /// * Right Identity: `append(a, empty()) = a`.
26 #[document_examples]
27 ///
28 /// Monoid laws for [`String`]:
29 ///
30 /// ```
31 /// use fp_library::functions::*;
32 ///
33 /// let a = "hello".to_string();
34 ///
35 /// // Left Identity: append(empty(), a) = a
36 /// assert_eq!(append(empty::<String>(), a.clone()), a);
37 ///
38 /// // Right Identity: append(a, empty()) = a
39 /// assert_eq!(append(a.clone(), empty::<String>()), a);
40 /// ```
41 ///
42 /// Monoid laws for [`Vec`]:
43 ///
44 /// ```
45 /// use fp_library::functions::*;
46 ///
47 /// let a = vec![1, 2, 3];
48 ///
49 /// // Left Identity: append(empty(), a) = a
50 /// assert_eq!(append(empty::<Vec<i32>>(), a.clone()), a);
51 ///
52 /// // Right Identity: append(a, empty()) = a
53 /// assert_eq!(append(a.clone(), empty::<Vec<i32>>()), a);
54 /// ```
55 pub trait Monoid: Semigroup {
56 /// The identity element.
57 ///
58 /// This method returns the identity element of the monoid.
59 #[document_signature]
60 ///
61 #[document_returns("The identity element.")]
62 #[document_examples]
63 ///
64 /// ```
65 /// use fp_library::functions::*;
66 ///
67 /// let x: String = empty();
68 /// assert_eq!(x, "".to_string());
69 /// ```
70 fn empty() -> Self;
71 }
72
73 /// The identity element.
74 ///
75 /// Free function version that dispatches to [the type class' associated function][`Monoid::empty`].
76 #[document_signature]
77 ///
78 #[document_type_parameters("The type of the monoid.")]
79 ///
80 #[document_returns("The identity element.")]
81 #[document_examples]
82 ///
83 /// ```
84 /// use fp_library::functions::*;
85 ///
86 /// let x: String = empty();
87 /// assert_eq!(x, "".to_string());
88 /// ```
89 pub fn empty<M: Monoid>() -> M {
90 M::empty()
91 }
92
93 /// Appends a value to itself a given number of times.
94 ///
95 /// Uses binary exponentiation for O(log n) appends.
96 #[document_signature]
97 ///
98 #[document_type_parameters("The monoid type.")]
99 ///
100 #[document_parameters("The value to exponentiate.", "The number of times to append.")]
101 ///
102 #[document_returns("The value appended to itself `n` times, or `empty()` if `n` is 0.")]
103 #[document_examples]
104 ///
105 /// ```
106 /// use fp_library::functions::*;
107 ///
108 /// assert_eq!(power("ab".to_string(), 3), "ababab");
109 /// assert_eq!(power("x".to_string(), 0), "");
110 /// assert_eq!(power(vec![1, 2], 2), vec![1, 2, 1, 2]);
111 /// ```
112 pub fn power<M: Monoid + Clone>(
113 a: M,
114 n: usize,
115 ) -> M {
116 if n == 0 {
117 M::empty()
118 } else if n == 1 {
119 a
120 } else if n.is_multiple_of(2) {
121 let half = power(a, n / 2);
122 M::append(half.clone(), half)
123 } else {
124 let rest = power(a.clone(), n - 1);
125 M::append(rest, a)
126 }
127 }
128}
129
130pub use inner::*;