scsys_traits/cont/
hkt.rs

1/*
2    Appellation: hkt <module>
3    Contrib: @FL03
4*/
5
6#[allow(dead_code)]
7mod old;
8
9#[allow(clippy::upper_case_acronyms)]
10/// The [`HKT`] trait defines an interface for higher-kinded types (HKT).
11pub trait HKT<T> {
12    type Cont<_T>;
13}
14
15/// The [`Functor`] trait extends the [`HKT`] trait to provide a way to map over its content(s)
16/// using a function `f` that transforms values of type `T` into values of type `U`.
17pub trait Functor<T>: HKT<T> {
18    fn fmap<F, U>(&self, f: F) -> Self::Cont<U>
19    where
20        F: Fn(&T) -> U;
21}
22
23/*
24 *************  Implementations  *************
25*/
26macro_rules! hkt {
27    (@impl $($t:ident)::*<$T:ident>) => {
28        impl<$T> HKT<$T> for $($t)::*<$T> {
29            type Cont<_T> = $($t)::*<_T>;
30        }
31    };
32    (
33        $(
34            $($t:ident)::*<$T:ident>
35        ),* $(,)?
36    ) => {
37        $(
38            hkt!(@impl $($t)::*<$T>);
39        )*
40    };
41}
42
43hkt! {
44    core::option::Option<T>
45}
46
47#[cfg(feature = "alloc")]
48hkt! {
49    alloc::vec::Vec<T>,
50    alloc::boxed::Box<T>,
51    alloc::rc::Rc<T>,
52    alloc::rc::Weak<T>,
53    alloc::sync::Arc<T>,
54    alloc::collections::BinaryHeap<T>,
55    alloc::collections::BTreeSet<T>,
56    alloc::collections::LinkedList<T>,
57    alloc::collections::VecDeque<T>,
58}
59
60#[cfg(feature = "std")]
61hkt! {
62    std::cell::Cell<T>,
63    std::cell::OnceCell<T>,
64    std::cell::RefCell<T>,
65    std::sync::Mutex<T>,
66    std::sync::RwLock<T>,
67    std::sync::LazyLock<T>,
68    std::collections::HashSet<V>,
69}
70
71#[cfg(feature = "alloc")]
72impl<K, V> HKT<V> for alloc::collections::BTreeMap<K, V> {
73    type Cont<U> = alloc::collections::BTreeMap<K, U>;
74}
75
76#[cfg(feature = "std")]
77impl<K, V> HKT<V> for std::collections::HashMap<K, V> {
78    type Cont<U> = std::collections::HashMap<K, U>;
79}
80
81impl<T> Functor<T> for Option<T> {
82    fn fmap<F, U>(&self, f: F) -> Self::Cont<U>
83    where
84        F: Fn(&T) -> U,
85    {
86        self.as_ref().map(f)
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn test_option() {
96        let opt = Some(42u8);
97        let opt2 = opt.fmap(|&x| x as usize + 1);
98        assert_eq!(opt2, Some(43_usize));
99    }
100}