fp_library/types/option.rs
1//! Implementations for [`Option`].
2
3use crate::{
4 classes::{
5 Applicative, ApplyFirst, ApplySecond, ClonableFn, Foldable, Functor, Pointed,
6 Semiapplicative, Semimonad, Traversable, clonable_fn::ApplyFn,
7 },
8 functions::{map, pure},
9 hkt::{Apply0L1T, Kind0L1T},
10};
11
12pub struct OptionBrand;
13
14impl Kind0L1T for OptionBrand {
15 type Output<A> = Option<A>;
16}
17
18impl Functor for OptionBrand {
19 /// # Examples
20 ///
21 /// ```
22 /// use fp_library::{brands::{OptionBrand, RcFnBrand}, functions::{identity, map}};
23 /// use std::rc::Rc;
24 ///
25 /// assert_eq!(
26 /// map::<RcFnBrand, OptionBrand, _, _>(Rc::new(identity::<()>))(None),
27 /// None
28 /// );
29 /// assert_eq!(
30 /// map::<RcFnBrand, OptionBrand, _, _>(Rc::new(identity))(Some(())),
31 /// Some(())
32 /// );
33 /// ```
34 fn map<'a, ClonableFnBrand: 'a + ClonableFn, A: 'a, B: 'a>(
35 f: ApplyFn<'a, ClonableFnBrand, A, B>
36 ) -> ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, Apply0L1T<Self, B>> {
37 ClonableFnBrand::new(move |fa: Apply0L1T<Self, _>| fa.map(&*f))
38 }
39}
40
41impl Semiapplicative for OptionBrand {
42 /// # Examples
43 ///
44 /// ```
45 /// use fp_library::{brands::{OptionBrand, RcFnBrand}, functions::{apply, identity}};
46 /// use std::rc::Rc;
47 ///
48 /// assert_eq!(
49 /// apply::<RcFnBrand, OptionBrand, (), ()>(None)(None),
50 /// None
51 /// );
52 /// assert_eq!(
53 /// apply::<RcFnBrand, OptionBrand, (), ()>(None)(Some(())),
54 /// None
55 /// );
56 /// assert_eq!(
57 /// apply::<RcFnBrand, OptionBrand, (), _>(Some(Rc::new(identity::<()>)))(None),
58 /// None
59 /// );
60 /// assert_eq!(
61 /// apply::<RcFnBrand, OptionBrand, (), _>(Some(Rc::new(identity)))(Some(())),
62 /// Some(())
63 /// );
64 /// ```
65 fn apply<'a, ClonableFnBrand: 'a + ClonableFn, A: 'a + Clone, B: 'a>(
66 ff: Apply0L1T<Self, ApplyFn<'a, ClonableFnBrand, A, B>>
67 ) -> ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, Apply0L1T<Self, B>> {
68 ClonableFnBrand::new(move |fa| match (ff.to_owned(), &fa) {
69 (Some(f), _) => map::<ClonableFnBrand, Self, _, _>(f)(fa),
70 _ => None::<B>,
71 })
72 }
73}
74
75impl ApplyFirst for OptionBrand {
76 /// # Examples
77 ///
78 /// ```
79 /// use fp_library::{brands::{OptionBrand, RcFnBrand}, functions::{apply_first, identity}};
80 /// use std::rc::Rc;
81 ///
82 /// assert_eq!(
83 /// apply_first::<RcFnBrand, OptionBrand, bool, bool>(None)(None),
84 /// None
85 /// );
86 /// assert_eq!(
87 /// apply_first::<RcFnBrand, OptionBrand, bool, _>(None)(Some(false)),
88 /// None
89 /// );
90 /// assert_eq!(
91 /// apply_first::<RcFnBrand, OptionBrand, _, bool>(Some(true))(None),
92 /// None
93 /// );
94 /// assert_eq!(
95 /// apply_first::<RcFnBrand, OptionBrand, _, _>(Some(true))(Some(false)),
96 /// Some(true)
97 /// );
98 /// ```
99 fn apply_first<'a, ClonableFnBrand: 'a + ClonableFn, A: 'a + Clone, B: Clone>(
100 fa: Apply0L1T<Self, A>
101 ) -> ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, B>, Apply0L1T<Self, A>> {
102 ClonableFnBrand::new(move |fb| match (fa.to_owned(), fb) {
103 (Some(a), Some(_)) => Some(a),
104 _ => None,
105 })
106 }
107}
108
109impl ApplySecond for OptionBrand {
110 /// # Examples
111 ///
112 /// ```
113 /// use fp_library::{brands::{OptionBrand, RcFnBrand}, functions::{apply_second, identity}};
114 /// use std::rc::Rc;
115 ///
116 /// assert_eq!(
117 /// apply_second::<RcFnBrand, OptionBrand, bool, bool>(None)(None),
118 /// None
119 /// );
120 /// assert_eq!(
121 /// apply_second::<RcFnBrand, OptionBrand, bool, _>(None)(Some(false)),
122 /// None
123 /// );
124 /// assert_eq!(
125 /// apply_second::<RcFnBrand, OptionBrand, _, bool>(Some(true))(None),
126 /// None
127 /// );
128 /// assert_eq!(
129 /// apply_second::<RcFnBrand, OptionBrand, _, _>(Some(true))(Some(false)),
130 /// Some(false)
131 /// );
132 /// ```
133 fn apply_second<'a, ClonableFnBrand: 'a + ClonableFn, A: 'a + Clone, B: 'a + Clone>(
134 fa: Apply0L1T<Self, A>
135 ) -> ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, B>, Apply0L1T<Self, B>> {
136 ClonableFnBrand::new(move |fb| match (fa.to_owned(), fb) {
137 (Some(_), Some(a)) => Some(a),
138 _ => None,
139 })
140 }
141}
142
143impl Pointed for OptionBrand {
144 /// # Examples
145 ///
146 /// ```
147 /// use fp_library::{brands::{OptionBrand, RcFnBrand}, functions::pure};
148 ///
149 /// assert_eq!(
150 /// pure::<RcFnBrand, OptionBrand, _>(()),
151 /// Some(())
152 /// );
153 fn pure<ClonableFnBrand: ClonableFn, A: Clone>(a: A) -> Apply0L1T<Self, A> {
154 Some(a)
155 }
156}
157
158impl Semimonad for OptionBrand {
159 /// # Examples
160 ///
161 /// ```
162 /// use fp_library::{brands::{OptionBrand, RcFnBrand}, functions::{bind, pure}};
163 /// use std::rc::Rc;
164 ///
165 /// assert_eq!(
166 /// bind::<RcFnBrand, OptionBrand, _, _>(None)(Rc::new(pure::<RcFnBrand, OptionBrand, ()>)),
167 /// None
168 /// );
169 /// assert_eq!(
170 /// bind::<RcFnBrand, OptionBrand, _, _>(Some(()))(Rc::new(pure::<RcFnBrand, OptionBrand, _>)),
171 /// Some(())
172 /// );
173 /// ```
174 fn bind<'a, ClonableFnBrand: 'a + ClonableFn, A: 'a + Clone, B: Clone>(
175 ma: Apply0L1T<Self, A>
176 ) -> ApplyFn<
177 'a,
178 ClonableFnBrand,
179 ApplyFn<'a, ClonableFnBrand, A, Apply0L1T<Self, B>>,
180 Apply0L1T<Self, B>,
181 > {
182 ClonableFnBrand::new(move |f: ApplyFn<'a, ClonableFnBrand, _, _>| {
183 ma.to_owned().and_then(|a| -> Option<B> { f(a) })
184 })
185 }
186}
187
188impl Foldable for OptionBrand {
189 /// # Examples
190 ///
191 /// ```
192 /// use fp_library::{brands::{OptionBrand, RcFnBrand}, functions::fold_right};
193 /// use std::rc::Rc;
194 ///
195 /// assert_eq!(
196 /// fold_right::<RcFnBrand, OptionBrand, _, _>(Rc::new(|a| Rc::new(move |b| a + b)))(1)(Some(1)),
197 /// 2
198 /// );
199 /// assert_eq!(
200 /// fold_right::<RcFnBrand, OptionBrand, i32, _>(Rc::new(|a| Rc::new(move |b| a + b)))(1)(None),
201 /// 1
202 /// );
203 /// ```
204 fn fold_right<'a, ClonableFnBrand: 'a + ClonableFn, A: Clone, B: Clone>(
205 f: ApplyFn<'a, ClonableFnBrand, A, ApplyFn<'a, ClonableFnBrand, B, B>>
206 ) -> ApplyFn<'a, ClonableFnBrand, B, ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, B>> {
207 ClonableFnBrand::new(move |b: B| {
208 ClonableFnBrand::new({
209 let f = f.clone();
210 move |fa| match (f.clone(), b.to_owned(), fa) {
211 (_, b, None) => b,
212 (f, b, Some(a)) => f(a)(b),
213 }
214 })
215 })
216 }
217}
218
219impl Traversable for OptionBrand {
220 /// # Examples
221 ///
222 /// ```
223 /// use fp_library::{brands::{OptionBrand, RcFnBrand}, functions::traverse};
224 /// use std::rc::Rc;
225 ///
226 /// assert_eq!(
227 /// traverse::<RcFnBrand, OptionBrand, OptionBrand, i32, i32>(Rc::new(|x| Some(x * 2)))(Some(3)),
228 /// Some(Some(6))
229 /// );
230 /// assert_eq!(
231 /// traverse::<RcFnBrand, OptionBrand, OptionBrand, i32, i32>(Rc::new(|x| Some(x * 2)))(None),
232 /// Some(None)
233 /// );
234 /// ```
235 fn traverse<'a, ClonableFnBrand: 'a + ClonableFn, F: Applicative, A: Clone, B: 'a + Clone>(
236 f: ApplyFn<'a, ClonableFnBrand, A, Apply0L1T<F, B>>
237 ) -> ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, Apply0L1T<F, Apply0L1T<Self, B>>>
238 where
239 Apply0L1T<F, B>: Clone,
240 Apply0L1T<F, ApplyFn<'a, ClonableFnBrand, Apply0L1T<Self, B>, Apply0L1T<Self, B>>>: Clone,
241 Apply0L1T<Self, B>: 'a,
242 Apply0L1T<Self, Apply0L1T<F, B>>: 'a,
243 {
244 ClonableFnBrand::new(move |ta: Apply0L1T<Self, _>| match (f.clone(), ta) {
245 (_, None) => pure::<ClonableFnBrand, F, _>(None),
246 (f, Some(a)) => map::<ClonableFnBrand, F, B, _>(ClonableFnBrand::new(
247 pure::<ClonableFnBrand, Self, _>,
248 ))(f(a)),
249 })
250 }
251}