partial_functional/monoid/
sum.rs

1use crate::semigroup::Semigroup;
2
3/// Semigroup of the Sum of type T if type T implements [std::ops::Add].
4/// ```
5/// # use partial_functional::prelude::*;
6///
7/// let five = Sum(5);
8/// let ten = Sum(10);
9///
10/// assert_eq!(Sum(15), five.combine(ten));
11/// ```
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
13pub struct Sum<T>(pub T);
14
15impl<T: Default + Semigroup> Default for Sum<T> {
16    fn default() -> Self {
17        Self(Default::default())
18    }
19}
20
21impl<T: PartialEq> PartialEq<T> for Sum<T> {
22    fn eq(&self, other: &T) -> bool {
23        self.0 == *other
24    }
25}
26
27impl<T: PartialOrd> PartialOrd<T> for Sum<T> {
28    fn partial_cmp(&self, other: &T) -> Option<std::cmp::Ordering> {
29        self.0.partial_cmp(other)
30    }
31}
32
33impl<T> From<T> for Sum<T> {
34    fn from(value: T) -> Self {
35        Self(value)
36    }
37}
38
39impl<T: std::ops::Add<Output = T>> Semigroup for Sum<T> {
40    fn combine(self, rhs: Self) -> Self {
41        Self(self.0 + rhs.0)
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use crate::monoid::Monoid;
48
49    use super::*;
50
51    use quickcheck::Arbitrary;
52    use quickcheck_macros::quickcheck;
53
54    impl Arbitrary for Sum<u32> {
55        fn arbitrary(g: &mut quickcheck::Gen) -> Self {
56            Sum(u8::arbitrary(g).into())
57        }
58
59        fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
60            Box::new(u32::shrink(&self.0).map(|x| x.into()))
61        }
62    }
63
64    #[quickcheck]
65    fn identity_property() {
66        assert_eq!(Sum::<u32>(0), Sum::empty())
67    }
68
69    #[quickcheck]
70    fn sum_of_vec_is_same_as_sum_combine(vec: Vec<u8>) -> bool {
71        let left: Sum<u32> = vec.iter().copied().map(|x| x as u32).sum::<u32>().into();
72        let right = vec
73            .iter()
74            .copied()
75            .map(|x| Sum::from(x as u32))
76            .fold(Sum::default(), |a, x| a.combine(x));
77
78        left == right
79    }
80
81    #[quickcheck]
82    fn associativity_property(x: Sum<u32>, y: Sum<u32>, z: Sum<u32>) -> bool {
83        x.combine(y.combine(z)) == x.combine(y).combine(z)
84    }
85}