1#[allow(dead_code)]
7mod old;
8
9#[allow(clippy::upper_case_acronyms)]
10pub trait HKT<T> {
12 type Cont<_T>;
13}
14
15pub 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
23macro_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}