1use crate::applicative::Applicative;
2use crate::hkt::OptionF;
3
4pub trait Selective: Applicative {
10 fn select<A, B, F>(fab: Self::Of<Result<A, B>>, ff: Self::Of<F>) -> Self::Of<B>
11 where
12 A: Clone,
13 F: Fn(A) -> B;
14}
15
16impl Selective for OptionF {
17 fn select<A, B, F>(fab: Option<Result<A, B>>, ff: Option<F>) -> Option<B>
18 where
19 A: Clone,
20 F: Fn(A) -> B,
21 {
22 match fab {
23 None => None,
24 Some(Ok(a)) => ff.map(|f| f(a)),
25 Some(Err(b)) => Some(b),
26 }
27 }
28}
29
30#[cfg(test)]
31mod tests {
32 use super::*;
33
34 #[test]
35 fn option_select_right() {
36 let result = OptionF::select(Some(Err(42i32)), Some(|_x: i32| 0));
37 assert_eq!(result, Some(42));
38 }
39
40 #[test]
41 fn option_select_left_with_fn() {
42 let result = OptionF::select(Some(Ok(3i32)), Some(|x: i32| x * 2));
43 assert_eq!(result, Some(6));
44 }
45
46 #[test]
47 fn option_select_left_no_fn() {
48 let result = OptionF::select(Some(Ok(3i32)), None::<fn(i32) -> i32>);
49 assert_eq!(result, None);
50 }
51
52 #[test]
53 fn option_select_none() {
54 let result = OptionF::select(None::<Result<i32, i32>>, Some(|x: i32| x * 2));
55 assert_eq!(result, None);
56 }
57}
58
59#[cfg(test)]
60mod law_tests {
61 use super::*;
62 use crate::functor::Functor;
63 use proptest::prelude::*;
64
65 proptest! {
66 #[test]
69 fn option_identity(x in any::<Option<i32>>()) {
70 let fab = OptionF::fmap(x, |b| Err::<i32, i32>(b));
71 let dummy: Option<fn(i32) -> i32> = Some(|_| panic!("should not be called"));
72 let result = OptionF::select(fab, dummy);
73 prop_assert_eq!(result, x);
74 }
75 }
76}