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