fp_library/classes/ref_alt.rs
1//! Choosing between values in a context by reference, associatively.
2//!
3//! `RefAlt` is to type constructors with by-reference access as
4//! [`Alt`](crate::classes::Alt) is to type constructors with by-value access.
5//! Both containers are borrowed, and `A: Clone` is required so elements can
6//! be cloned out of the references when constructing the result.
7//!
8//! ### Examples
9//!
10//! ```
11//! use fp_library::{
12//! brands::*,
13//! classes::*,
14//! functions::explicit::*,
15//! };
16//!
17//! let x: Option<i32> = None;
18//! let y = Some(5);
19//! let z = alt::<OptionBrand, _, _, _>(&x, &y);
20//! assert_eq!(z, Some(5));
21//! ```
22
23#[fp_macros::document_module]
24mod inner {
25 use {
26 crate::{
27 classes::*,
28 kinds::*,
29 },
30 fp_macros::*,
31 };
32
33 /// A type class for associative choice on type constructors, operating by reference.
34 ///
35 /// `RefAlt` is the by-reference counterpart of [`Alt`]. Where `Alt` consumes
36 /// its arguments, `RefAlt` borrows both containers and clones elements as
37 /// needed to produce the result. This is useful for memoized or shared types
38 /// that only expose `&A` access.
39 ///
40 /// ### Laws
41 ///
42 /// `RefAlt` instances must satisfy the following law:
43 /// * Associativity: `ref_alt(&ref_alt(&x, &y), &z) = ref_alt(&x, &ref_alt(&y, &z))`.
44 #[document_examples]
45 ///
46 /// RefAlt associativity for [`Option`]:
47 ///
48 /// ```
49 /// use fp_library::{
50 /// brands::*,
51 /// classes::*,
52 /// functions::explicit::*,
53 /// };
54 ///
55 /// // Associativity: ref_alt(&ref_alt(&x, &y), &z) = ref_alt(&x, &ref_alt(&y, &z))
56 /// let x: Option<i32> = None;
57 /// let y = Some(1);
58 /// let z = Some(2);
59 /// assert_eq!(
60 /// alt::<OptionBrand, _, _, _>(&alt::<OptionBrand, _, _, _>(&x, &y), &z),
61 /// alt::<OptionBrand, _, _, _>(&x, &alt::<OptionBrand, _, _, _>(&y, &z)),
62 /// );
63 /// ```
64 #[kind(type Of<'a, A: 'a>: 'a;)]
65 pub trait RefAlt: RefFunctor {
66 /// Chooses between two values in a context, operating by reference.
67 ///
68 /// Both containers are borrowed. Elements are cloned as needed to
69 /// construct the result.
70 #[document_signature]
71 ///
72 #[document_type_parameters(
73 "The lifetime of the values.",
74 "The type of the value inside the context."
75 )]
76 ///
77 #[document_parameters("The first value.", "The second value.")]
78 ///
79 #[document_returns("The chosen/combined value.")]
80 #[document_examples]
81 ///
82 /// ```
83 /// use fp_library::{
84 /// brands::*,
85 /// classes::*,
86 /// functions::explicit::*,
87 /// };
88 ///
89 /// let x: Option<i32> = None;
90 /// let y = Some(5);
91 /// let z = alt::<OptionBrand, _, _, _>(&x, &y);
92 /// assert_eq!(z, Some(5));
93 /// ```
94 fn ref_alt<'a, A: 'a + Clone>(
95 fa1: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
96 fa2: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
97 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>);
98 }
99
100 /// Chooses between two values in a context, operating by reference.
101 ///
102 /// Free function version that dispatches to [the type class' associated function][`RefAlt::ref_alt`].
103 #[document_signature]
104 ///
105 #[document_type_parameters(
106 "The lifetime of the values.",
107 "The brand of the context.",
108 "The type of the value inside the context."
109 )]
110 ///
111 #[document_parameters("The first value.", "The second value.")]
112 ///
113 #[document_returns("The chosen/combined value.")]
114 #[document_examples]
115 ///
116 /// ```
117 /// use fp_library::{
118 /// brands::*,
119 /// classes::*,
120 /// functions::explicit::*,
121 /// };
122 ///
123 /// let x: Option<i32> = None;
124 /// let y = Some(5);
125 /// let z = alt::<OptionBrand, _, _, _>(&x, &y);
126 /// assert_eq!(z, Some(5));
127 /// ```
128 pub fn ref_alt<'a, Brand: RefAlt, A: 'a + Clone>(
129 fa1: &Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
130 fa2: &Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
131 ) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
132 Brand::ref_alt(fa1, fa2)
133 }
134}
135
136pub use inner::*;