Skip to main content

fp_library/types/
additive.rs

1//! A newtype wrapper whose [`Semigroup`](crate::classes::Semigroup) and [`Monoid`](crate::classes::Monoid) instances use addition
2//! from [`Semiring`](crate::classes::Semiring).
3//!
4//! ### Examples
5//!
6//! ```
7//! use fp_library::{
8//! 	functions::*,
9//! 	types::Additive,
10//! };
11//!
12//! let x = Additive(3i32);
13//! let y = Additive(4i32);
14//! assert_eq!(append(x, y), Additive(7));
15//! assert_eq!(empty::<Additive<i32>>(), Additive(0));
16//! ```
17
18#[fp_macros::document_module]
19mod inner {
20	use {
21		crate::classes::*,
22		fp_macros::*,
23	};
24
25	/// A newtype wrapper whose [`Semigroup`] instance uses [`Semiring::add`].
26	///
27	/// This provides a canonical [`Monoid`] for numeric types based on addition,
28	/// with [`Semiring::zero`] as the identity element.
29	#[document_examples]
30	///
31	/// ```
32	/// use fp_library::{
33	/// 	functions::*,
34	/// 	types::Additive,
35	/// };
36	///
37	/// assert_eq!(append(Additive(2i32), Additive(3)), Additive(5));
38	/// assert_eq!(empty::<Additive<i32>>(), Additive(0));
39	/// ```
40	#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
41	pub struct Additive<A>(
42		/// The wrapped value.
43		pub A,
44	);
45
46	#[document_type_parameters("The semiring type.")]
47	impl<A: Semiring> Semigroup for Additive<A> {
48		/// Combines two values using [`Semiring::add`].
49		#[document_signature]
50		///
51		#[document_parameters("The first additive value.", "The second additive value.")]
52		///
53		#[document_returns("The sum wrapped in `Additive`.")]
54		#[document_examples]
55		///
56		/// ```
57		/// use fp_library::{
58		/// 	functions::*,
59		/// 	types::Additive,
60		/// };
61		///
62		/// assert_eq!(append(Additive(10i32), Additive(20)), Additive(30));
63		/// ```
64		fn append(
65			a: Self,
66			b: Self,
67		) -> Self {
68			Additive(A::add(a.0, b.0))
69		}
70	}
71
72	#[document_type_parameters("The semiring type.")]
73	impl<A: Semiring> Monoid for Additive<A> {
74		/// Returns `Additive(zero())`.
75		#[document_signature]
76		///
77		#[document_returns("The additive identity wrapped in `Additive`.")]
78		#[document_examples]
79		///
80		/// ```
81		/// use fp_library::{
82		/// 	functions::*,
83		/// 	types::Additive,
84		/// };
85		///
86		/// assert_eq!(empty::<Additive<i32>>(), Additive(0));
87		/// ```
88		fn empty() -> Self {
89			Additive(A::zero())
90		}
91	}
92}
93
94pub use inner::*;
95
96#[cfg(test)]
97mod tests {
98	use {
99		super::*,
100		crate::functions::*,
101		quickcheck_macros::quickcheck,
102	};
103
104	#[quickcheck]
105	fn semigroup_associativity(
106		a: i32,
107		b: i32,
108		c: i32,
109	) -> bool {
110		let x = Additive(a);
111		let y = Additive(b);
112		let z = Additive(c);
113		append(x, append(y, z)) == append(append(x, y), z)
114	}
115
116	#[quickcheck]
117	fn monoid_left_identity(a: i32) -> bool {
118		let x = Additive(a);
119		append(empty::<Additive<i32>>(), x) == x
120	}
121
122	#[quickcheck]
123	fn monoid_right_identity(a: i32) -> bool {
124		let x = Additive(a);
125		append(x, empty::<Additive<i32>>()) == x
126	}
127}