1use crate::{
4 Apply,
5 brands::OptionBrand,
6 classes::{
7 applicative::Applicative, apply_first::ApplyFirst, apply_second::ApplySecond,
8 clonable_fn::ClonableFn, foldable::Foldable, functor::Functor, lift::Lift, monoid::Monoid,
9 pointed::Pointed, semiapplicative::Semiapplicative, semimonad::Semimonad,
10 traversable::Traversable,
11 },
12 impl_kind,
13 kinds::*,
14};
15
16impl_kind! {
17 for OptionBrand {
18 type Of<'a, A: 'a>: 'a = Option<A>;
19 }
20}
21
22impl Functor for OptionBrand {
23 fn map<'a, A: 'a, B: 'a, F>(
48 f: F,
49 fa: Apply!(
50 brand: Self,
51 signature: ('a, A: 'a) -> 'a,
52 ),
53 ) -> Apply!(
54 brand: Self,
55 signature: ('a, B: 'a) -> 'a,
56 )
57 where
58 F: Fn(A) -> B + 'a,
59 {
60 fa.map(f)
61 }
62}
63
64impl Lift for OptionBrand {
65 fn lift2<'a, A, B, C, F>(
91 f: F,
92 fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
93 fb: Apply!(brand: Self, signature: ('a, B: 'a) -> 'a),
94 ) -> Apply!(brand: Self, signature: ('a, C: 'a) -> 'a)
95 where
96 F: Fn(A, B) -> C + 'a,
97 A: 'a,
98 B: 'a,
99 C: 'a,
100 {
101 fa.zip(fb).map(|(a, b)| f(a, b))
102 }
103}
104
105impl Pointed for OptionBrand {
106 fn pure<'a, A: 'a>(a: A) -> Apply!(brand: Self, signature: ('a, A: 'a) -> 'a) {
129 Some(a)
130 }
131}
132
133impl ApplyFirst for OptionBrand {}
134impl ApplySecond for OptionBrand {}
135
136impl Semiapplicative for OptionBrand {
137 fn apply<'a, A: 'a + Clone, B: 'a, FnBrand: 'a + ClonableFn>(
165 ff: Apply!(brand: Self, signature: ('a, Apply!(brand: FnBrand, kind: ClonableFn, lifetimes: ('a), types: (A, B)): 'a) -> 'a),
166 fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
167 ) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a) {
168 match (ff, fa) {
169 (Some(f), Some(a)) => Some(f(a)),
170 _ => None,
171 }
172 }
173}
174
175impl Semimonad for OptionBrand {
176 fn bind<'a, A: 'a, B: 'a, F>(
201 ma: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
202 f: F,
203 ) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a)
204 where
205 F: Fn(A) -> Apply!(brand: Self, signature: ('a, B: 'a) -> 'a) + 'a,
206 {
207 ma.and_then(f)
208 }
209}
210
211impl Foldable for OptionBrand {
212 fn fold_right<'a, A: 'a, B: 'a, F>(
238 f: F,
239 init: B,
240 fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
241 ) -> B
242 where
243 F: Fn(A, B) -> B + 'a,
244 {
245 match fa {
246 Some(a) => f(a, init),
247 None => init,
248 }
249 }
250
251 fn fold_left<'a, A: 'a, B: 'a, F>(
276 f: F,
277 init: B,
278 fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
279 ) -> B
280 where
281 F: Fn(B, A) -> B + 'a,
282 {
283 match fa {
284 Some(a) => f(init, a),
285 None => init,
286 }
287 }
288
289 fn fold_map<'a, A: 'a, M, F>(
314 f: F,
315 fa: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
316 ) -> M
317 where
318 M: Monoid + 'a,
319 F: Fn(A) -> M + 'a,
320 {
321 match fa {
322 Some(a) => f(a),
323 None => M::empty(),
324 }
325 }
326}
327
328impl Traversable for OptionBrand {
329 fn traverse<'a, F: Applicative, A: 'a + Clone, B: 'a + Clone, Func>(
353 f: Func,
354 ta: Apply!(brand: Self, signature: ('a, A: 'a) -> 'a),
355 ) -> Apply!(brand: F, signature: ('a, Apply!(brand: Self, signature: ('a, B: 'a) -> 'a): 'a) -> 'a)
356 where
357 Func: Fn(A) -> Apply!(brand: F, signature: ('a, B: 'a) -> 'a) + 'a,
358 Apply!(brand: Self, signature: ('a, B: 'a) -> 'a): Clone,
359 {
360 match ta {
361 Some(a) => F::map(|b| Some(b), f(a)),
362 None => F::pure(None),
363 }
364 }
365
366 fn sequence<'a, F: Applicative, A: 'a + Clone>(
389 ta: Apply!(brand: Self, signature: ('a, Apply!(brand: F, signature: ('a, A: 'a) -> 'a): 'a) -> 'a)
390 ) -> Apply!(brand: F, signature: ('a, Apply!(brand: Self, signature: ('a, A: 'a) -> 'a): 'a) -> 'a)
391 where
392 Apply!(brand: F, signature: ('a, A: 'a) -> 'a): Clone,
393 Apply!(brand: Self, signature: ('a, A: 'a) -> 'a): Clone,
394 {
395 match ta {
396 Some(fa) => F::map(|a| Some(a), fa),
397 None => F::pure(None),
398 }
399 }
400}
401
402#[cfg(test)]
403mod tests {
404 use super::*;
405 use crate::{
406 brands::RcFnBrand,
407 classes::{functor::map, pointed::pure, semiapplicative::apply, semimonad::bind},
408 functions::{compose, identity},
409 };
410 use quickcheck_macros::quickcheck;
411
412 #[quickcheck]
416 fn functor_identity(x: Option<i32>) -> bool {
417 map::<OptionBrand, _, _, _>(identity, x) == x
418 }
419
420 #[quickcheck]
422 fn functor_composition(x: Option<i32>) -> bool {
423 let f = |x: i32| x.wrapping_add(1);
424 let g = |x: i32| x.wrapping_mul(2);
425 map::<OptionBrand, _, _, _>(compose(f, g), x)
426 == map::<OptionBrand, _, _, _>(f, map::<OptionBrand, _, _, _>(g, x))
427 }
428
429 #[quickcheck]
433 fn applicative_identity(v: Option<i32>) -> bool {
434 apply::<OptionBrand, _, _, RcFnBrand>(
435 pure::<OptionBrand, _>(<RcFnBrand as ClonableFn>::new(identity)),
436 v,
437 ) == v
438 }
439
440 #[quickcheck]
442 fn applicative_homomorphism(x: i32) -> bool {
443 let f = |x: i32| x.wrapping_mul(2);
444 apply::<OptionBrand, _, _, RcFnBrand>(
445 pure::<OptionBrand, _>(<RcFnBrand as ClonableFn>::new(f)),
446 pure::<OptionBrand, _>(x),
447 ) == pure::<OptionBrand, _>(f(x))
448 }
449
450 #[quickcheck]
452 fn applicative_composition(
453 w: Option<i32>,
454 u_is_some: bool,
455 v_is_some: bool,
456 ) -> bool {
457 let v_fn = |x: i32| x.wrapping_mul(2);
458 let u_fn = |x: i32| x.wrapping_add(1);
459
460 let v = if v_is_some {
461 pure::<OptionBrand, _>(<RcFnBrand as ClonableFn>::new(v_fn))
462 } else {
463 None
464 };
465 let u = if u_is_some {
466 pure::<OptionBrand, _>(<RcFnBrand as ClonableFn>::new(u_fn))
467 } else {
468 None
469 };
470
471 let vw = apply::<OptionBrand, _, _, RcFnBrand>(v.clone(), w.clone());
473 let rhs = apply::<OptionBrand, _, _, RcFnBrand>(u.clone(), vw);
474
475 let uv = match (u, v) {
478 (Some(uf), Some(vf)) => {
479 let composed = move |x| uf(vf(x));
480 Some(<RcFnBrand as ClonableFn>::new(composed))
481 }
482 _ => None,
483 };
484
485 let lhs = apply::<OptionBrand, _, _, RcFnBrand>(uv, w);
486
487 lhs == rhs
488 }
489
490 #[quickcheck]
492 fn applicative_interchange(y: i32) -> bool {
493 let f = |x: i32| x.wrapping_mul(2);
495 let u = pure::<OptionBrand, _>(<RcFnBrand as ClonableFn>::new(f));
496
497 let lhs = apply::<OptionBrand, _, _, RcFnBrand>(u.clone(), pure::<OptionBrand, _>(y));
498
499 let rhs_fn = <RcFnBrand as ClonableFn>::new(move |f: std::rc::Rc<dyn Fn(i32) -> i32>| f(y));
500 let rhs = apply::<OptionBrand, _, _, RcFnBrand>(pure::<OptionBrand, _>(rhs_fn), u);
501
502 lhs == rhs
503 }
504
505 #[quickcheck]
509 fn monad_left_identity(a: i32) -> bool {
510 let f = |x: i32| Some(x.wrapping_mul(2));
511 bind::<OptionBrand, _, _, _>(pure::<OptionBrand, _>(a), f) == f(a)
512 }
513
514 #[quickcheck]
516 fn monad_right_identity(m: Option<i32>) -> bool {
517 bind::<OptionBrand, _, _, _>(m, pure::<OptionBrand, _>) == m
518 }
519
520 #[quickcheck]
522 fn monad_associativity(m: Option<i32>) -> bool {
523 let f = |x: i32| Some(x.wrapping_mul(2));
524 let g = |x: i32| Some(x.wrapping_add(1));
525 bind::<OptionBrand, _, _, _>(bind::<OptionBrand, _, _, _>(m, f), g)
526 == bind::<OptionBrand, _, _, _>(m, |x| bind::<OptionBrand, _, _, _>(f(x), g))
527 }
528
529 #[test]
533 fn map_none() {
534 assert_eq!(map::<OptionBrand, _, _, _>(|x: i32| x + 1, None), None);
535 }
536
537 #[test]
539 fn bind_none() {
540 assert_eq!(bind::<OptionBrand, _, _, _>(None, |x: i32| Some(x + 1)), None);
541 }
542
543 #[test]
545 fn bind_returning_none() {
546 assert_eq!(bind::<OptionBrand, _, _, _>(Some(5), |_| None::<i32>), None);
547 }
548
549 #[test]
551 fn fold_right_none() {
552 assert_eq!(
553 crate::classes::foldable::fold_right::<OptionBrand, _, _, _>(
554 |x: i32, acc| x + acc,
555 0,
556 None
557 ),
558 0
559 );
560 }
561
562 #[test]
564 fn fold_left_none() {
565 assert_eq!(
566 crate::classes::foldable::fold_left::<OptionBrand, _, _, _>(
567 |acc, x: i32| acc + x,
568 0,
569 None
570 ),
571 0
572 );
573 }
574
575 #[test]
577 fn traverse_none() {
578 assert_eq!(
579 crate::classes::traversable::traverse::<OptionBrand, OptionBrand, _, _, _>(
580 |x: i32| Some(x + 1),
581 None
582 ),
583 Some(None)
584 );
585 }
586
587 #[test]
589 fn traverse_returning_none() {
590 assert_eq!(
591 crate::classes::traversable::traverse::<OptionBrand, OptionBrand, _, _, _>(
592 |_: i32| None::<i32>,
593 Some(5)
594 ),
595 None
596 );
597 }
598}