1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
use crate::classes::{Applicative, Apply, Foldable, Functor, Monad, Monoid, Semigroup}; use crate::plug::{Plug, Unplug}; impl<A> Unplug for Option<A> { type F = Option<A>; type A = A; } impl<A, B> Plug<B> for Option<A> { type Out = Option<B>; } impl<A> Functor for Option<A> { fn fmap<B, F>(self, f: F) -> <Self as Plug<B>>::Out where F: FnOnce(<Self as Unplug>::A) -> B, { self.map(f) } } impl<A> Apply for Option<A> { fn ap<B, F>(self, f: <Self as Plug<F>>::Out) -> <Self as Plug<B>>::Out where F: FnOnce(<Self as Unplug>::A) -> B, { match f { Some(fun) => self.map(fun), None => None, } } } impl<A> Applicative for Option<A> { fn pure(value: A) -> Self { Some(value) } } impl<A> Monad for Option<A> { fn bind<B, F>(self, f: F) -> <Self as Plug<B>>::Out where F: FnOnce(<Self as Unplug>::A) -> <Self as Plug<B>>::Out, { self.and_then(f) } } impl<A: Semigroup> Semigroup for Option<A> { fn combine(self, other: Option<A>) -> Option<A> { match (self, other) { (a, None) => a, (None, b) => b, (Some(a), Some(b)) => Some(a.combine(b)), } } } impl<A: Semigroup> Monoid for Option<A> { fn mempty() -> Self { None } } impl<A> Foldable for Option<A> { fn fold_left<B, F>(self, init: B, f: F) -> B where F: FnOnce(B, <Self as Unplug>::A) -> B, { match self { Some(a) => f(init, a), None => init, } } } #[cfg(test)] mod tests { use crate::classes::*; impl Semigroup for i32 { fn combine(self, other: i32) -> i32 { self + other } } #[test] fn test_monoid() { assert_eq!(Option::<i32>::mempty(), None); assert_eq!(Semigroup::combine(1, 2), 3); assert_eq!(Option::mempty().combine(Some(1)).combine(Some(2)), Some(3)); } #[test] fn test_functor_applicative_monad() { assert_eq!(Some(2).fmap(|a| a + 1), Some(3)); assert_eq!(None.fmap(|a: i32| a + 1), None); assert_eq!(Option::pure(2), Some(2)); assert_eq!(Some(2).ap(Some(|a| a + 1)), Some(3)); assert_eq!(Some(2).ap::<i32, fn(i32) -> i32>(None), None); assert_eq!(None.ap(Some(|a: i32| a + 1)), None); assert_eq!(Some(2).bind(|a: i32| a.checked_add(1)), Some(3)); assert_eq!(None.bind(|a: i32| a.checked_add(1)), None); assert_eq!(Some(2).bind(|_| None::<i32>), None); } }