rust2fun/
higher.rs

1//! Implementation of Higher Kinded Types for Rust.
2//!
3//! A higher kinded type is a concept that reifies a type constructor as an actual type.
4//!
5//! A type constructor can be thought of in these analogies:
6//! * like a function in the type universe
7//! * as a type with a "hole" in it
8//! * as a container containing type(s)
9//! * as a generic type, parameterised over other types
10//! * as an endofunctor in the category of types
11//!
12//! To be able to use them in places where concrete "proper" types are usually expected, a language
13//! must support the concept of higher kinded types. Although Rust lacks in a native support for HKT,
14//! we always have a walk around called Lightweight Higher Kinded Type.
15//!
16//! # See also
17//!
18//! * [Lightweight Higher Kinded Type](https://www.cl.cam.ac.uk/~jdy22/papers/lightweight-higher-kinded-polymorphism.pdf)
19//! * [Rust/Haskell: Higher-Kinded Types (HKT)](https://gist.github.com/CMCDragonkai/a5638f50c87d49f815b8)
20
21use core::marker::PhantomData;
22
23/// Implementation of Lightweight Higher Kinded Type for a type of kind `* -> *`.
24pub trait Higher {
25    /// Type parameter abstracted by Higher, e.g. `Option<Param>`.
26    type Param;
27    /// Swapped higher type, e.g. Target = `Option<T>`.
28    type Target<T>: Higher<Param = T>;
29
30    /// Unsafe cast from one [Higher] type to another. This is a safe operation as long as the
31    /// resulting type is the same as the original type. Might be useful for building abstractions.
32    fn unsafe_cast<T, R>(self) -> R
33    where
34        Self: Higher<Param = T> + Sized,
35        R: Higher<Param = T>,
36    {
37        let ptr = &self as *const _ as *const R;
38        let result = unsafe { core::ptr::read_volatile(ptr) };
39        core::mem::forget(self);
40        result
41    }
42}
43
44/// Implementation of Higher Kinded Type for a type of kind `*, * -> *, *`.
45pub trait Higher2 {
46    /// First type parameter abstracted by Higher2, e.g. `Result<Param1, _>`.
47    type Param1;
48    /// Second type parameter abstracted by Higher2, e.g. `Result<_, Param2>`.
49    type Param2;
50    /// Swapped higher type for 2 types, e.g. Target = `Result<T1, T2>`.
51    type Target<T1, T2>: Higher2<Param1 = T1, Param2 = T2>;
52}
53
54/// Macro implementing `Higher` for a given type of kind `* -> *`.
55///
56/// # Example
57///
58/// ```
59/// use rust2fun::prelude::*;
60///
61/// struct Unary<T>(T);
62/// higher!(Unary);
63/// ```
64/// This will implement `Higher` for `Unary` as follows:
65/// ```
66/// use rust2fun::prelude::*;
67///
68/// struct Unary<T>(T);
69///
70/// impl<P> Higher for Unary<P> {
71///     type Param = P;
72///     type Target<T> = Unary<T>;
73/// }
74/// ```
75#[macro_export]
76macro_rules! higher {
77    ($t:ident) => {
78        impl<P> $crate::higher::Higher for $t<P> {
79            type Param = P;
80            type Target<T> = $t<T>;
81        }
82    };
83}
84
85higher!(Option);
86higher!(PhantomData);
87
88impl<P, E> Higher for Result<P, E> {
89    type Param = P;
90    type Target<T> = Result<T, E>;
91}
92
93impl<P, E> Higher2 for Result<P, E> {
94    type Param1 = P;
95    type Param2 = E;
96    type Target<TP, TE> = Result<TP, TE>;
97}
98
99impl<A, B> Higher2 for (A, B) {
100    type Param1 = A;
101    type Param2 = B;
102    type Target<TA, TB> = (TA, TB);
103}
104
105if_std! {
106    use std::boxed::Box;
107    use std::collections::*;
108    use std::vec::Vec;
109
110    higher!(Vec);
111    higher!(Box);
112    higher!(LinkedList);
113    higher!(BinaryHeap);
114    higher!(BTreeSet);
115    higher!(VecDeque);
116    higher!(HashSet);
117
118    impl<K, V> Higher for HashMap<K, V> {
119        type Param = V;
120        type Target<T> = HashMap<K, T>;
121    }
122
123    impl<K, V> Higher2 for HashMap<K, V>{
124        type Param1 = K;
125        type Param2 = V;
126        type Target<TK, TV> = HashMap<TK, TV>;
127    }
128}