fp_library/classes/plus.rs
1//! The identity element for [`Alt`](crate::classes::Alt), forming a monoid on type constructors.
2//!
3//! `Plus` is to type constructors as [`Monoid`](crate::classes::Monoid) is to concrete types.
4//!
5//! ### Examples
6//!
7//! ```
8//! use fp_library::{
9//! brands::*,
10//! classes::*,
11//! functions::*,
12//! };
13//!
14//! let x = alt::<OptionBrand, _>(plus_empty::<OptionBrand, i32>(), Some(5));
15//! assert_eq!(x, Some(5));
16//! ```
17
18#[fp_macros::document_module]
19mod inner {
20 use {
21 crate::{
22 classes::*,
23 kinds::*,
24 },
25 fp_macros::*,
26 };
27
28 /// A type class extending [`Alt`] with an identity element.
29 ///
30 /// `Plus` is similar to [`Monoid`], except that it applies to types of
31 /// kind `* -> *` (like `Option` or `Vec`) rather than concrete types.
32 ///
33 /// ### Laws
34 ///
35 /// `Plus` instances must satisfy the following laws:
36 /// * Left identity: `alt(empty, x) = x`.
37 /// * Right identity: `alt(x, empty) = x`.
38 /// * Annihilation: `map(f, empty) = empty`.
39 #[document_examples]
40 ///
41 /// Plus laws for [`Option`]:
42 ///
43 /// ```
44 /// use fp_library::{
45 /// brands::*,
46 /// classes::*,
47 /// functions::*,
48 /// };
49 ///
50 /// // Left identity: alt(empty, x) = x
51 /// let x = Some(5);
52 /// assert_eq!(alt::<OptionBrand, _>(plus_empty::<OptionBrand, i32>(), x), x,);
53 ///
54 /// // Right identity: alt(x, empty) = x
55 /// assert_eq!(alt::<OptionBrand, _>(x, plus_empty::<OptionBrand, i32>()), x,);
56 ///
57 /// // Annihilation: map(f, empty) = empty
58 /// let f = |i: i32| i * 2;
59 /// assert_eq!(
60 /// map::<OptionBrand, _, _>(f, plus_empty::<OptionBrand, i32>()),
61 /// plus_empty::<OptionBrand, i32>(),
62 /// );
63 /// ```
64 pub trait Plus: Alt {
65 /// Returns the identity element for [`alt`](Alt::alt).
66 ///
67 /// This is the empty/failure value for the type constructor.
68 /// For `Option`, this is `None`. For `Vec`, this is `vec![]`.
69 #[document_signature]
70 ///
71 #[document_type_parameters(
72 "The lifetime of the value.",
73 "The type of the value inside the context."
74 )]
75 ///
76 #[document_returns("The identity element.")]
77 #[document_examples]
78 ///
79 /// ```
80 /// use fp_library::{
81 /// brands::*,
82 /// functions::*,
83 /// };
84 ///
85 /// let x: Option<i32> = plus_empty::<OptionBrand, i32>();
86 /// assert_eq!(x, None);
87 /// ```
88 fn empty<'a, A: 'a>() -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>);
89 }
90
91 /// Returns the identity element for [`alt`](crate::classes::Alt::alt).
92 ///
93 /// Free function version that dispatches to [the type class' associated function][`Plus::empty`].
94 #[document_signature]
95 ///
96 #[document_type_parameters(
97 "The lifetime of the value.",
98 "The brand of the context.",
99 "The type of the value inside the context."
100 )]
101 ///
102 #[document_returns("The identity element.")]
103 #[document_examples]
104 ///
105 /// ```
106 /// use fp_library::{
107 /// brands::*,
108 /// functions::*,
109 /// };
110 ///
111 /// let x: Option<i32> = plus_empty::<OptionBrand, i32>();
112 /// assert_eq!(x, None);
113 /// ```
114 pub fn empty<'a, Brand: Plus, A: 'a>()
115 -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
116 Brand::empty()
117 }
118}
119
120pub use inner::*;