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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! A `Traversable` with an additional index.
#[fp_macros::document_module]
mod inner {
use {
crate::classes::*,
fp_macros::*,
};
/// A `Traversable` with an additional index.
///
/// A `TraversableWithIndex` is a `Traversable` that also allows you to access the
/// index of each element when traversing the structure. The index type is
/// uniquely determined by the implementing brand via the [`WithIndex`] supertype.
///
/// ### Laws
///
/// `TraversableWithIndex` instances must be compatible with their `Traversable` instance:
/// * Compatibility with Traversable: `traverse(f, fa) = traverse_with_index(|_, a| f(a), fa)`.
#[document_examples]
///
/// TraversableWithIndex laws for [`Vec`]:
///
/// ```
/// use fp_library::{
/// brands::*,
/// classes::traversable_with_index::TraversableWithIndex,
/// functions::explicit::*,
/// };
///
/// let xs = vec![1, 2, 3];
/// let f = |a: i32| if a > 0 { Some(a * 2) } else { None };
///
/// // Compatibility with Traversable:
/// // traverse(f, fa) = traverse_with_index(|_, a| f(a), fa)
/// assert_eq!(
/// traverse::<RcFnBrand, VecBrand, _, _, OptionBrand, _, _>(f, xs.clone()),
/// VecBrand::traverse_with_index::<i32, i32, OptionBrand>(|_, a| f(a), xs),
/// );
/// ```
pub trait TraversableWithIndex: Traversable + FoldableWithIndex + FunctorWithIndex {
/// Traverse the structure with an effectful function, providing the index of each element.
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The type of the elements.",
"The type of the result inside the applicative.",
"The applicative type."
)]
#[document_parameters(
"The function to apply to each element and its index.",
"The structure to traverse."
)]
#[document_returns("The structure of results inside the applicative.")]
#[document_examples]
///
/// ```
/// use fp_library::{
/// brands::{
/// OptionBrand,
/// VecBrand,
/// },
/// classes::traversable_with_index::TraversableWithIndex,
/// };
///
/// let result = VecBrand::traverse_with_index::<i32, i32, OptionBrand>(
/// |_i, x| if x > 0 { Some(x * 2) } else { None },
/// vec![1, 2, 3],
/// );
/// assert_eq!(result, Some(vec![2, 4, 6]));
/// ```
fn traverse_with_index<'a, A: 'a, B: 'a + Clone, M: Applicative>(
f: impl Fn(Self::Index, A) -> M::Of<'a, B> + 'a,
ta: Self::Of<'a, A>,
) -> M::Of<'a, Self::Of<'a, B>>
where
Self::Of<'a, B>: Clone,
M::Of<'a, B>: Clone, {
Self::sequence::<B, M>(Self::map_with_index::<A, M::Of<'a, B>>(f, ta))
}
}
/// Traverses a structure with an indexed effectful function.
///
/// Free function version that dispatches to [the type class' associated function][`TraversableWithIndex::traverse_with_index`].
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The brand of the traversable structure.",
"The type of the elements.",
"The type of the result elements.",
"The applicative brand for the effect."
)]
#[document_parameters("The indexed effectful function.", "The structure to traverse.")]
#[document_returns("The traversed structure wrapped in the applicative effect.")]
#[document_examples]
///
/// ```
/// use fp_library::{
/// brands::{
/// OptionBrand,
/// RcFnBrand,
/// VecBrand,
/// },
/// functions::explicit::*,
/// };
///
/// let result = traverse_with_index::<RcFnBrand, VecBrand, _, _, OptionBrand, _, _>(
/// |_i, x: i32| if x > 0 { Some(x * 2) } else { None },
/// vec![1, 2, 3],
/// );
/// assert_eq!(result, Some(vec![2, 4, 6]));
/// ```
pub fn traverse_with_index<
'a,
Brand: TraversableWithIndex,
A: 'a,
B: 'a + Clone,
M: Applicative,
>(
f: impl Fn(Brand::Index, A) -> M::Of<'a, B> + 'a,
ta: Brand::Of<'a, A>,
) -> M::Of<'a, Brand::Of<'a, B>>
where
Brand::Of<'a, B>: Clone,
M::Of<'a, B>: Clone, {
Brand::traverse_with_index::<A, B, M>(f, ta)
}
}
pub use inner::*;