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
//! Some FP traits.

use itertools::Itertools;

/// A trait for types of kind * -> *
pub trait Kind1To1 {
    type Constructor<S>;
    // where
    //     Self::Constructor<S>: Kind1To1; // : ?Sized
}

/// A trait for types that can be mapped over to obtain an instance of "the same type" with a
/// different type parameter.
pub trait Functor<T>: Kind1To1 {
    fn fmap<S>(self, f: impl FnMut(T) -> S) -> Self::Constructor<S>;
    // where
    //     Self::Constructor<S>: Kind1To1;
    // where
    //     Self::Constructor<S>: Functor<S>;
}

/// A trait for types that can be mapped over by reference.
pub trait FunctorRef<T>: Kind1To1 {
    fn fmap_ref<S>(&self, f: impl FnMut(&T) -> S) -> Self::Constructor<S>;
    // where
    //     Self::Constructor<S>: Kind1To1;
    // where
    //     Self::Constructor<S>: FunctorRef<S>;
}

impl<T> Kind1To1 for Vec<T> {
    type Constructor<S> = Vec<S>;
}

impl<T> Functor<T> for Vec<T> {
    fn fmap<S>(self, f: impl FnMut(T) -> S) -> Vec<S> {
        self.into_iter().map(f).collect()
    }
}

impl<T> FunctorRef<T> for Vec<T> {
    fn fmap_ref<S>(&self, f: impl FnMut(&T) -> S) -> Vec<S> {
        self.iter().map(f).collect()
    }
}

impl<T, const N: usize> Kind1To1 for [T; N] {
    type Constructor<S> = [S; N];
}

impl<T, const N: usize> Functor<T> for [T; N] {
    fn fmap<S>(self, f: impl FnMut(T) -> S) -> [S; N] {
        self.map(f)
    }
}

impl<T, const N: usize> FunctorRef<T> for [T; N] {
    fn fmap_ref<S>(&self, f: impl FnMut(&T) -> S) -> [S; N] {
        unsafe {
            self.iter()
                .map(f)
                .collect_vec() // this really isn't great but apparently there's not really a better way to do this currently
                .try_into()
                .unwrap_unchecked()
        }
    }
}

impl<T> Kind1To1 for Box<[T]> {
    type Constructor<S> = Box<[S]>;
}

impl<T> Functor<T> for Box<[T]> {
    fn fmap<S>(self, f: impl FnMut(T) -> S) -> Box<[S]> {
        Vec::from(self).fmap(f).into_boxed_slice()
    }
}

impl<T> FunctorRef<T> for Box<[T]> {
    fn fmap_ref<S>(&self, f: impl FnMut(&T) -> S) -> Box<[S]> {
        self.iter().map(f).collect_vec().into_boxed_slice()
    }
}
// Only implementable if `Constructor<S>` is `?Sized` in trait def
// impl<T> Kind1To1 for [T] {
//     type Constructor<S> = [S];
// }