1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//! Alternative functors, combining [`Applicative`](crate::classes::Applicative) and [`Plus`](crate::classes::Plus).
//!
//! `Alternative` provides the ability to choose between computations (via [`Alt`](crate::classes::Alt))
//! with an identity element (via [`Plus`](crate::classes::Plus)), combined with applicative
//! lifting (via [`Applicative`](crate::classes::Applicative)).
//!
//! ### Examples
//!
//! ```
//! use fp_library::{
//! brands::*,
//! classes::*,
//! functions::*,
//! };
//!
//! // guard filters based on a condition
//! let result: Vec<()> = guard::<VecBrand>(true);
//! assert_eq!(result, vec![()]);
//!
//! let result: Vec<()> = guard::<VecBrand>(false);
//! assert_eq!(result, vec![]);
//! ```
#[fp_macros::document_module]
mod inner {
use {
crate::{
classes::*,
kinds::*,
},
fp_macros::*,
};
/// A type class combining [`Applicative`] and [`Plus`].
///
/// `Alternative` has no members of its own; it specifies that the type
/// constructor has both [`Applicative`] and [`Plus`] instances.
///
/// ### Laws
///
/// `Alternative` instances must satisfy the following laws:
/// * Distributivity: `apply(alt(f, g), x) = alt(apply(f, x), apply(g, x))`.
/// * Annihilation: `apply(empty, f) = empty`.
#[document_examples]
///
/// Alternative laws for [`Vec`]:
///
/// ```
/// use fp_library::{
/// brands::*,
/// classes::*,
/// functions::*,
/// };
///
/// // Annihilation: apply(empty, f) = empty
/// let f: Vec<i32> = vec![1, 2, 3];
/// let empty_fns: Vec<std::rc::Rc<dyn Fn(i32) -> i32>> = plus_empty::<VecBrand, _>();
/// let result = apply(empty_fns, f);
/// assert_eq!(result, plus_empty::<VecBrand, i32>());
/// ```
pub trait Alternative: Applicative + Plus {}
/// Blanket implementation of [`Alternative`].
#[document_type_parameters("The brand type.")]
impl<Brand> Alternative for Brand where Brand: Applicative + Plus {}
/// Fails using [`Plus`] if a condition does not hold, or succeeds using
/// [`Applicative`] if it does.
///
/// This is useful in monadic/applicative comprehensions to filter results.
#[document_signature]
///
#[document_type_parameters(
"The lifetime of the values.",
"The brand of the alternative functor."
)]
///
#[document_parameters("The condition to check.")]
///
#[document_returns("`pure(())` if the condition is `true`, `empty` otherwise.")]
#[document_examples]
///
/// ```
/// use fp_library::{
/// brands::*,
/// classes::*,
/// functions::*,
/// };
///
/// // Using guard to filter in a Vec comprehension
/// let result: Vec<()> = guard::<VecBrand>(true);
/// assert_eq!(result, vec![()]);
///
/// let result: Vec<()> = guard::<VecBrand>(false);
/// assert_eq!(result, vec![]);
/// ```
pub fn guard<'a, Brand: Alternative>(
condition: bool
) -> Apply!(<Brand as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, ()>) {
if condition { Brand::pure(()) } else { Brand::empty() }
}
}
pub use inner::*;