1use crate::{
4 brands::{Brand, Brand1},
5 functions::map,
6 hkt::{Apply, Kind, Kind1},
7 typeclasses::{Apply as TypeclassApply, ApplyFirst, ApplySecond, Bind, Functor, Pure},
8};
9
10pub struct OptionBrand;
12
13impl<A> Kind1<A> for OptionBrand {
14 type Output = Option<A>;
15}
16
17impl<A> Brand1<Option<A>, A> for OptionBrand {
18 fn inject(a: Option<A>) -> Apply<Self, (A,)> {
19 a
20 }
21 fn project(a: Apply<Self, (A,)>) -> Option<A> {
22 a
23 }
24}
25
26impl Pure for OptionBrand {
27 fn pure<A>(a: A) -> Apply<Self, (A,)>
34 where
35 Self: Kind<(A,)>,
36 {
37 <Self as Brand<_, _>>::inject(Some(a))
38 }
39}
40
41impl Functor for OptionBrand {
42 fn map<F, A, B>(f: F) -> impl Fn(Apply<Self, (A,)>) -> Apply<Self, (B,)>
51 where
52 Self: Kind<(A,)> + Kind<(B,)>,
53 F: Fn(A) -> B,
54 {
55 move |fa| <Self as Brand<_, _>>::inject(<Self as Brand<_, _>>::project(fa).map(&f))
56 }
57}
58
59impl TypeclassApply for OptionBrand {
60 fn apply<F, A, B>(ff: Apply<Self, (F,)>) -> impl Fn(Apply<Self, (A,)>) -> Apply<Self, (B,)>
71 where
72 Self: Kind<(F,)> + Kind<(A,)> + Kind<(B,)>,
73 F: Fn(A) -> B,
74 Apply<Self, (F,)>: Clone,
75 {
76 move |fa| match (<Self as Brand<_, _>>::project(ff.to_owned()), &fa) {
77 (Some(f), _) => map::<Self, F, _, _>(f)(fa),
78 _ => <Self as Brand<_, _>>::inject(None::<B>),
79 }
80 }
81}
82
83impl ApplyFirst for OptionBrand {
84 fn apply_first<A, B>(fa: Apply<Self, (A,)>) -> impl Fn(Apply<Self, (B,)>) -> Apply<Self, (A,)>
95 where
96 Self: Kind<(A,)> + Kind<(B,)>,
97 Apply<Self, (A,)>: Clone,
98 {
99 move |fb| {
100 <Self as Brand<_, (A,)>>::inject(
101 match (
102 <Self as Brand<_, _>>::project(fa.to_owned()),
103 <Self as Brand<_, (B,)>>::project(fb),
104 ) {
105 (Some(a), Some(_)) => Some(a),
106 _ => None,
107 },
108 )
109 }
110 }
111}
112
113impl ApplySecond for OptionBrand {
114 fn apply_second<A, B>(_fa: Apply<Self, (A,)>) -> impl Fn(Apply<Self, (B,)>) -> Apply<Self, (B,)>
125 where
126 Self: Kind<(A,)> + Kind<(B,)>,
127 Apply<Self, (A,)>: Clone,
128 {
129 move |fb| {
130 <Self as Brand<_, (B,)>>::inject(
131 match (
132 <Self as Brand<_, (A,)>>::project(_fa.to_owned()),
133 <Self as Brand<_, (B,)>>::project(fb),
134 ) {
135 (Some(_), Some(a)) => Some(a),
136 _ => None,
137 },
138 )
139 }
140 }
141}
142
143impl Bind for OptionBrand {
144 fn bind<F, A, B>(ma: Apply<Self, (A,)>) -> impl Fn(F) -> Apply<Self, (B,)>
153 where
154 Self: Kind<(A,)> + Kind<(B,)> + Sized,
155 F: Fn(A) -> Apply<Self, (B,)>,
156 Apply<Self, (A,)>: Clone,
157 {
158 move |f| {
159 <Self as Brand<_, _>>::inject(
160 <Self as Brand<_, _>>::project(ma.to_owned())
161 .and_then(|a| -> Option<B> { <Self as Brand<_, _>>::project(f(a)) }),
162 )
163 }
164 }
165}