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::ApplyClonableFn,
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: ApplyClonableFn<'a, ClonableFnBrand, A, B>
36	) -> ApplyClonableFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, Apply0L1T<Self, B>> {
37		<ClonableFnBrand as ClonableFn>::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, ApplyClonableFn<'a, ClonableFnBrand, A, B>>
67	) -> ApplyClonableFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, Apply0L1T<Self, B>> {
68		<ClonableFnBrand as ClonableFn>::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	) -> ApplyClonableFn<'a, ClonableFnBrand, Apply0L1T<Self, B>, Apply0L1T<Self, A>> {
102		<ClonableFnBrand as ClonableFn>::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	) -> ApplyClonableFn<'a, ClonableFnBrand, Apply0L1T<Self, B>, Apply0L1T<Self, B>> {
136		<ClonableFnBrand as ClonableFn>::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	) -> ApplyClonableFn<
177		'a,
178		ClonableFnBrand,
179		ApplyClonableFn<'a, ClonableFnBrand, A, Apply0L1T<Self, B>>,
180		Apply0L1T<Self, B>,
181	> {
182		<ClonableFnBrand as ClonableFn>::new(
183			move |f: ApplyClonableFn<'a, ClonableFnBrand, _, _>| {
184				ma.to_owned().and_then(|a| -> Option<B> { f(a) })
185			},
186		)
187	}
188}
189
190impl Foldable for OptionBrand {
191	/// # Examples
192	///
193	/// ```
194	/// use fp_library::{brands::{OptionBrand, RcFnBrand}, functions::fold_right};
195	/// use std::rc::Rc;
196	///
197	/// assert_eq!(
198	///     fold_right::<RcFnBrand, OptionBrand, _, _>(Rc::new(|a| Rc::new(move |b| a + b)))(1)(Some(1)),
199	///     2
200	/// );
201	/// assert_eq!(
202	///     fold_right::<RcFnBrand, OptionBrand, i32, _>(Rc::new(|a| Rc::new(move |b| a + b)))(1)(None),
203	///     1
204	/// );
205	/// ```
206	fn fold_right<'a, ClonableFnBrand: 'a + ClonableFn, A: Clone, B: Clone>(
207		f: ApplyClonableFn<'a, ClonableFnBrand, A, ApplyClonableFn<'a, ClonableFnBrand, B, B>>
208	) -> ApplyClonableFn<
209		'a,
210		ClonableFnBrand,
211		B,
212		ApplyClonableFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, B>,
213	> {
214		<ClonableFnBrand as ClonableFn>::new(move |b: B| {
215			<ClonableFnBrand as ClonableFn>::new({
216				let f = f.clone();
217				move |fa| match (f.clone(), b.to_owned(), fa) {
218					(_, b, None) => b,
219					(f, b, Some(a)) => f(a)(b),
220				}
221			})
222		})
223	}
224}
225
226impl Traversable for OptionBrand {
227	/// # Examples
228	///
229	/// ```
230	/// use fp_library::{brands::{OptionBrand, RcFnBrand}, functions::traverse};
231	/// use std::rc::Rc;
232	///
233	/// assert_eq!(
234	///     traverse::<RcFnBrand, OptionBrand, OptionBrand, i32, i32>(Rc::new(|x| Some(x * 2)))(Some(3)),
235	///     Some(Some(6))
236	/// );
237	/// assert_eq!(
238	///     traverse::<RcFnBrand, OptionBrand, OptionBrand, i32, i32>(Rc::new(|x| Some(x * 2)))(None),
239	///     Some(None)
240	/// );
241	/// ```
242	fn traverse<'a, ClonableFnBrand: 'a + ClonableFn, F: Applicative, A: Clone, B: 'a + Clone>(
243		f: ApplyClonableFn<'a, ClonableFnBrand, A, Apply0L1T<F, B>>
244	) -> ApplyClonableFn<'a, ClonableFnBrand, Apply0L1T<Self, A>, Apply0L1T<F, Apply0L1T<Self, B>>>
245	where
246		Apply0L1T<F, B>: Clone,
247		Apply0L1T<F, ApplyClonableFn<'a, ClonableFnBrand, Apply0L1T<Self, B>, Apply0L1T<Self, B>>>:
248			Clone,
249		Apply0L1T<Self, B>: 'a,
250		Apply0L1T<Self, Apply0L1T<F, B>>: 'a,
251	{
252		<ClonableFnBrand as ClonableFn>::new(move |ta: Apply0L1T<Self, _>| match (f.clone(), ta) {
253			(_, None) => pure::<ClonableFnBrand, F, _>(None),
254			(f, Some(a)) => map::<ClonableFnBrand, F, B, _>(<ClonableFnBrand as ClonableFn>::new(
255				pure::<ClonableFnBrand, Self, _>,
256			))(f(a)),
257		})
258	}
259}