meowth/core/
applicative.rs

1//! Applicative
2
3use crate::core::*;
4
5/// `Applicative` is a [`Functor`] with a [`pure`](Applicative::pure) method
6///
7/// REF
8/// - [nLab](https://ncatlab.org/nlab/show/applicative+functor)
9pub trait Applicative: Functor + Monoidal {
10    /// `pure` lifts a value into the applicative functor.
11    ///
12    /// # Example
13    ///
14    /// ```
15    /// use meowth::core::*;
16    ///
17    /// let x = Option::pure(1);
18    /// assert_eq!(x, Some(1));
19    /// ```
20    fn pure<A>(a: A) -> Self::Wrapped<A>
21    where
22        Self: Id<Self::Wrapped<A>>,
23        for<'a> A: Clone + 'a;
24
25    /// `ap` applies a function to the value
26    fn ap<B, F>(self, ff: Self::Wrapped<F>) -> Self::Wrapped<B>
27    where
28        for<'a> F: Fn(Self::Unwrapped) -> B + 'a;
29
30    /// `ap2` applies a function to two values
31    ///
32    /// This should be really simple to implement, but not easy to provide a
33    /// default implementation due to the type system.
34    ///
35    /// # Example
36    ///
37    /// ```
38    /// use meowth::core::*;
39    ///
40    /// let x = Some(1);
41    /// let y = Some(2.0);
42    /// let z = Some(|a: i32, b: f64| a as f64 + b);
43    /// let w = x.ap2(y, z);
44    /// assert_eq!(w, Some(3.0));
45    /// ```
46    fn ap2<B, C, F>(self, _b: Self::Wrapped<B>, _f: Self::Wrapped<F>) -> Self::Wrapped<C>
47    where
48        for<'a> F: Fn(Self::Unwrapped, B) -> C + 'a,
49        for<'a> B: 'a,
50    {
51        unimplemented!()
52    }
53}
54
55impl<T> Applicative for Option<T> {
56    fn pure<A>(a: A) -> Option<A> {
57        Some(a)
58    }
59
60    fn ap<B, F>(self, ff: Option<F>) -> Option<B>
61    where
62        F: Fn(T) -> B,
63    {
64        match (self, ff) {
65            (Some(a), Some(f)) => Some(f(a)),
66            _ => None,
67        }
68    }
69
70    fn ap2<B, C, F>(self, b: Option<B>, f: Option<F>) -> Option<C>
71    where
72        for<'a> F: Fn(T, B) -> C + 'a,
73        for<'a> B: 'a,
74    {
75        match self.product(b).product(f) {
76            Some(((a, b), f)) => Some(f(a, b)),
77            _ => None,
78        }
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    #[test]
87    fn test_applicative() {
88        let x = Option::pure(1);
89        assert_eq!(x, Some(1));
90
91        let x = Some(1);
92        let y = Some(2.0);
93        let z = x.product(y);
94        assert_eq!(z, Some((1, 2.0)));
95
96        let x = Some(1);
97        let y = Some(|x: i32| x as f64 / 2.0);
98        let z = x.ap(y);
99        assert_eq!(z, Some(0.5));
100
101        let x = None;
102        let y = Some(|x: i32| x as f64 / 2.0);
103        let z = x.ap(y);
104        assert_eq!(z, None);
105
106        let x = Some(1);
107        let y = Some(2.0);
108        let z = Some(|a: i32, b: f64| a as f64 + b);
109        let w = x.ap2(y, z);
110        assert_eq!(w, Some(3.0));
111    }
112}