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