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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//! Implementation of Higher Kinded Types for Rust.
//!
//! A higher kinded type is a concept that reifies a type constructor as an actual type.
//!
//! A type constructor can be thought of in these analogies:
//! * like a function in the type universe
//! * as a type with a "hole" in it
//! * as a container containing type(s)
//! * as a generic type, parameterised over other types
//! * as an endofunctor in the category of types
//!
//! To be able to use them in places where concrete "proper" types are usually expected, a language
//! must support the concept of higher kinded types. Although Rust lacks in a native support for HKT,
//! we always have a walk around called Lightweight Higher Kinded Type.
//!
//! # See also
//!
//! * [Lightweight Higher Kinded Type](https://www.cl.cam.ac.uk/~jdy22/papers/lightweight-higher-kinded-polymorphism.pdf)
//! * [Rust/Haskell: Higher-Kinded Types (HKT)](https://gist.github.com/CMCDragonkai/a5638f50c87d49f815b8)

use core::marker::PhantomData;

/// Implementation of Lightweight Higher Kinded Type for a type of kind `* -> *`.
pub trait Higher {
    /// Type parameter abstracted by Higher, e.g. `Option<Param>`.
    type Param;
    /// Swapped higher type, e.g. Target = `Option<T>`.
    type Target<T>: Higher<Param = T>;

    /// Unsafe cast from one [Higher] type to another. This is a safe operation as long as the
    /// resulting type is the same as the original type. Might be useful for building abstractions.
    fn unsafe_cast<T, R>(self) -> R
    where
        Self: Higher<Param = T> + Sized,
        R: Higher<Param = T>,
    {
        let ptr = &self as *const _ as *const R;
        let result = unsafe { core::ptr::read_volatile(ptr) };
        core::mem::forget(self);
        result
    }
}

/// Implementation of Higher Kinded Type for a type of kind `*, * -> *, *`.
pub trait Higher2 {
    /// First type parameter abstracted by Higher2, e.g. `Result<Param1, _>`.
    type Param1;
    /// Second type parameter abstracted by Higher2, e.g. `Result<_, Param2>`.
    type Param2;
    /// Swapped higher type for 2 types, e.g. Target = `Result<T1, T2>`.
    type Target<T1, T2>: Higher2<Param1 = T1, Param2 = T2>;
}

/// Macro implementing `Higher` for a given type of kind `* -> *`.
///
/// # Example
///
/// ```
/// use rust2fun::prelude::*;
///
/// struct Unary<T>(T);
/// higher!(Unary);
/// ```
/// This will implement `Higher` for `Unary` as follows:
/// ```
/// use rust2fun::prelude::*;
///
/// struct Unary<T>(T);
///
/// impl<P> Higher for Unary<P> {
///     type Param = P;
///     type Target<T> = Unary<T>;
/// }
/// ```
#[macro_export]
macro_rules! higher {
    ($t:ident) => {
        impl<P> $crate::higher::Higher for $t<P> {
            type Param = P;
            type Target<T> = $t<T>;
        }
    };
}

higher!(Option);
higher!(PhantomData);

impl<P, E> Higher for Result<P, E> {
    type Param = P;
    type Target<T> = Result<T, E>;
}

impl<P, E> Higher2 for Result<P, E> {
    type Param1 = P;
    type Param2 = E;
    type Target<TP, TE> = Result<TP, TE>;
}

impl<A, B> Higher2 for (A, B) {
    type Param1 = A;
    type Param2 = B;
    type Target<TA, TB> = (TA, TB);
}

if_std! {
    use std::boxed::Box;
    use std::collections::*;
    use std::vec::Vec;

    higher!(Vec);
    higher!(Box);
    higher!(LinkedList);
    higher!(BinaryHeap);
    higher!(BTreeSet);
    higher!(VecDeque);
    higher!(HashSet);

    impl<K, V> Higher for HashMap<K, V> {
        type Param = V;
        type Target<T> = HashMap<K, T>;
    }

    impl<K, V> Higher2 for HashMap<K, V>{
        type Param1 = K;
        type Param2 = V;
        type Target<TK, TV> = HashMap<TK, TV>;
    }
}