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
use crate::functor::Functor;
pub trait Applicative: Functor {
fn pure(a: Self::Inner) -> Self::Wrapped<Self::Inner>;
fn seq<F: Fn(Self::Inner) -> B, B>(f: F, fa: Self::Wrapped<Self::Inner>) -> Self::Wrapped<B>;
fn lift_a2<F: Fn(Self::Inner, B) -> C, B, C>(
f: F,
fa: Self::Wrapped<Self::Inner>,
fb: Self::Wrapped<B>,
) -> Self::Wrapped<C>;
}
impl<A> Applicative for Option<A> {
#[inline]
fn pure(val: Self::Inner) -> Self::Wrapped<A> {
Some(val)
}
#[inline]
fn seq<F: Fn(Self::Inner) -> B, B>(f: F, fa: Self::Wrapped<Self::Inner>) -> Self::Wrapped<B> {
match fa {
Some(a) => Some(f(a)),
_ => None,
}
}
#[inline]
fn lift_a2<F: Fn(Self::Inner, B) -> C, B, C>(
f: F,
fa: Self::Wrapped<Self::Inner>,
fb: Self::Wrapped<B>,
) -> Self::Wrapped<C> {
match (fa, fb) {
(Some(a), Some(b)) => Some(f(a, b)),
_ => None,
}
}
}
impl<T, E> Applicative for Result<T, E> {
#[inline]
fn pure(val: Self::Inner) -> Self::Wrapped<Self::Inner> {
Ok(val)
}
#[inline]
fn lift_a2<F: Fn(Self::Inner, B) -> C, B, C>(
f: F,
fa: Self::Wrapped<Self::Inner>,
fb: Self::Wrapped<B>,
) -> Self::Wrapped<C> {
match (fa, fb) {
(Ok(a), Ok(b)) => Ok(f(a, b)),
(Err(e), _) | (_, Err(e)) => Err(e),
}
}
#[inline]
fn seq<F: Fn(Self::Inner) -> B, B>(f: F, fa: Self::Wrapped<Self::Inner>) -> Self::Wrapped<B> {
match fa {
Ok(a) => Ok(f(a)),
Err(e) => Err(e),
}
}
}
#[cfg(test)]
mod test {
use super::Applicative;
#[test]
fn applicative_pure() {
assert_eq!(<Option<u32> as Applicative>::pure(20), Some(20));
}
#[test]
fn applicative_option_some_lift_a2() {
let plus = |x: u32, y: u32| x + y;
assert_eq!(
<Option<u32> as Applicative>::lift_a2(plus, Some(1730), Some(8)),
Some(1738)
);
}
#[test]
fn applicative_option_none_lift_a2() {
let plus = |x: u32, y: u32| x + y;
assert_eq!(
<Option<u32> as Applicative>::lift_a2(plus, None, None),
None
);
}
#[test]
fn applicative_option_some_none_lift_a2() {
let plus = |x: u32, y: u32| x + y;
assert_eq!(
<Option<u32> as Applicative>::lift_a2(plus, None, Some(1738)),
None
);
}
}