partial_functional/monoid/
sum.rs1use crate::semigroup::Semigroup;
2
3#[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}