Skip to main content

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::*;