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	#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
41	#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
42	pub struct Additive<A>(
43		/// The wrapped value.
44		pub A,
45	);
46
47	#[document_type_parameters("The semiring type.")]
48	impl<A: Semiring> Semigroup for Additive<A> {
49		/// Combines two values using [`Semiring::add`].
50		#[document_signature]
51		///
52		#[document_parameters("The first additive value.", "The second additive value.")]
53		///
54		#[document_returns("The sum wrapped in `Additive`.")]
55		#[document_examples]
56		///
57		/// ```
58		/// use fp_library::{
59		/// 	functions::*,
60		/// 	types::Additive,
61		/// };
62		///
63		/// assert_eq!(append(Additive(10i32), Additive(20)), Additive(30));
64		/// ```
65		fn append(
66			a: Self,
67			b: Self,
68		) -> Self {
69			Additive(A::add(a.0, b.0))
70		}
71	}
72
73	#[document_type_parameters("The semiring type.")]
74	impl<A: Semiring> Monoid for Additive<A> {
75		/// Returns `Additive(zero())`.
76		#[document_signature]
77		///
78		#[document_returns("The additive identity wrapped in `Additive`.")]
79		#[document_examples]
80		///
81		/// ```
82		/// use fp_library::{
83		/// 	functions::*,
84		/// 	types::Additive,
85		/// };
86		///
87		/// assert_eq!(empty::<Additive<i32>>(), Additive(0));
88		/// ```
89		fn empty() -> Self {
90			Additive(A::zero())
91		}
92	}
93}
94
95pub use inner::*;
96
97#[cfg(test)]
98mod tests {
99	use {
100		super::*,
101		crate::functions::*,
102		quickcheck_macros::quickcheck,
103	};
104
105	#[quickcheck]
106	fn semigroup_associativity(
107		a: i32,
108		b: i32,
109		c: i32,
110	) -> bool {
111		let x = Additive(a);
112		let y = Additive(b);
113		let z = Additive(c);
114		append(x, append(y, z)) == append(append(x, y), z)
115	}
116
117	#[quickcheck]
118	fn monoid_left_identity(a: i32) -> bool {
119		let x = Additive(a);
120		append(empty::<Additive<i32>>(), x) == x
121	}
122
123	#[quickcheck]
124	fn monoid_right_identity(a: i32) -> bool {
125		let x = Additive(a);
126		append(x, empty::<Additive<i32>>()) == x
127	}
128}