fp_library/typeclasses/semigroup.rs
1use crate::typeclasses::{ClonableFn, clonable_fn::ApplyFn};
2
3/// A typeclass for semigroups.
4///
5/// A `Semigroup` is a set equipped with an associative binary operation.
6/// This means for any elements `a`, `b`, and `c` in the set, the operation
7/// satisfies: `(a <> b) <> c = a <> (b <> c)`.
8///
9/// In functional programming, semigroups are useful for combining values
10/// in a consistent way. They form the basis for more complex structures
11/// like monoids.
12///
13/// # Laws
14///
15/// Semigroup instances must satisfy the associative law:
16/// * Associativity: `append(append(x)(y))(z) = append(x)(append(y)(z))`.
17///
18/// # Examples
19///
20/// Common semigroups include:
21/// * Strings with concatenation.
22/// * Numbers with addition.
23/// * Numbers with multiplication.
24/// * Lists with concatenation.
25pub trait Semigroup {
26 /// Associative operation that combines two values of the same type.
27 ///
28 /// # Type Signature
29 ///
30 /// `forall a. Semigroup a => a -> a -> a`
31 ///
32 /// # Parameters
33 ///
34 /// * `a`: First value to combine.
35 /// * `b`: Second value to combine.
36 ///
37 /// # Returns
38 ///
39 /// The result of combining the two values using the semigroup operation.
40 fn append<'a, ClonableFnBrand: 'a + ClonableFn>(
41 a: Self
42 ) -> ApplyFn<'a, ClonableFnBrand, Self, Self>
43 where
44 Self: Sized;
45}
46
47/// Associative operation that combines two values of the same type.
48///
49/// Free function version that dispatches to [the typeclass' associated function][`Semigroup::append`].
50///
51/// # Type Signature
52///
53/// `forall a. Semigroup a => a -> a -> a`
54///
55/// # Parameters
56///
57/// * `a`: First value to combine.
58/// * `b`: Second value to combine.
59///
60/// # Returns
61///
62/// The result of combining the two values using the semigroup operation.
63///
64/// # Examples
65///
66/// ```
67/// use fp_library::{brands::RcFnBrand, functions::append};
68///
69/// assert_eq!(
70/// append::<RcFnBrand, String>("Hello, ".to_string())("World!".to_string()),
71/// "Hello, World!"
72/// );
73/// ```
74pub fn append<'a, ClonableFnBrand: 'a + ClonableFn, Brand: Semigroup + Sized>(
75 a: Brand
76) -> ApplyFn<'a, ClonableFnBrand, Brand, Brand> {
77 Brand::append::<'a, ClonableFnBrand>(a)
78}
79
80// #[cfg(test)]
81// mod tests {
82// use crate::{brands::RcFnBrand, functions::append};
83
84// #[test]
85// fn test_string_semigroup() {
86// let s1 = "Hello, ".to_string();
87// let s2 = "World!".to_string();
88// assert_eq!(append::<String, RcFnBrand>(s1)(s2), "Hello, World!");
89// }
90
91// #[test]
92// fn test_string_semigroup_associativity() {
93// let s1 = "a".to_string();
94// let s2 = "b".to_string();
95// let s3 = "c".to_string();
96
97// // (a <> b) <> c = a <> (b <> c)
98// let left_associated =
99// append::<String, RcFnBrand>(append::<String, RcFnBrand>(s1.clone())(s2.clone()))(s3.clone());
100// let right_associated =
101// append::<String, RcFnBrand>(s1.clone())(append::<String, RcFnBrand>(s2.clone())(s3.clone()));
102
103// assert_eq!(left_associated, right_associated);
104// assert_eq!(left_associated, "abc");
105// }
106// }