rspace_traits/
functor.rs

1/*
2    Appellation: hkt <module>
3    Contrib: @FL03
4*/
5
6/// The [`Functor`] trait describes an interface for a higher-kinded type that can be mapped
7/// over. The trait is parameterized over a function `F` and a target type `T`, allowing for
8/// granular control over the mapping process itself, relying on associated types like
9/// `Cont<U>` to define the resulting container type after the mapping operation and the
10/// `Elem` type to specify the type of elements contained within the functor _**before**_
11/// the mapping operation is applied. Moreover, the `apply` method takes ownership of the
12/// functor allowing for distinct implementations for referenced, mutabled, and owned
13/// instances.
14pub trait Functor<F, T>
15where
16    F: FnOnce(Self::Elem) -> T,
17{
18    type Cont<U>: ?Sized;
19    type Elem;
20
21    fn apply(self, f: F) -> Self::Cont<T>;
22}
23
24pub trait FunctorIter<F, T>
25where
26    F: FnOnce(Self::Elem) -> T,
27{
28    type Cont<U>: ?Sized;
29    type Iter;
30    type Elem;
31
32    fn apply_all(self, f: F) -> Self::Cont<T>;
33}
34
35// pub trait Applicative<T>: Functor<T> {
36//     fn pure(value: T) -> Self::Cont<T>;
37// }
38
39// pub trait Monad<T>: Applicative<T> {
40//     fn flat_map<F, U>(&self, f: F) -> Self::Cont<U>
41//     where
42//         F: Fn(&mut T, &T) -> Self::Cont<U>;
43// }
44
45/*
46 *************  Implementations  *************
47*/
48impl<U, V, F> Functor<F, V> for Option<U>
49where
50    F: FnOnce(U) -> V,
51{
52    type Cont<T> = Option<T>;
53    type Elem = U;
54
55    fn apply(self, f: F) -> Self::Cont<V> {
56        self.map(f)
57    }
58}
59
60impl<'a, U, V, F> Functor<F, V> for &'a Option<U>
61where
62    F: FnOnce(&U) -> V,
63{
64    type Cont<T> = Option<T>;
65    type Elem = &'a U;
66
67    fn apply(self, f: F) -> Self::Cont<V> {
68        self.as_ref().map(|x| f(x))
69    }
70}
71
72impl<F, X, Y, S, I> FunctorIter<F, Y> for S
73where
74    S: IntoIterator<Item = X, IntoIter = I>,
75    F: FnMut(X) -> Y,
76    I: Iterator<Item = X>,
77{
78    type Cont<U> = core::iter::Map<<S as IntoIterator>::IntoIter, F>;
79    type Iter = I;
80    type Elem = X;
81
82    fn apply_all(self, f: F) -> Self::Cont<Y> {
83        self.into_iter().map(f)
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn test_option() {
93        fn sample(input: u8) -> f32 {
94            input as f32 + 1.25
95        }
96        assert_eq! {
97            Some(42u8).apply(sample),
98            Some(43.25)
99        }
100    }
101}