fp_library/macros/
hkt.rs

1//! Contains the macro to generate boilerplate for [HKTs][crate::hkt] and the generated code.
2
3use crate::{
4	brands::Brand,
5	hkt::{Apply, Kind},
6};
7
8/// Macro to generate boilerplate for [HKTs][crate::hkt] of a specific arity.
9macro_rules! hkt {
10	(
11		// Kind trait name (e.g., Kind1).
12		$KindN:ident,
13		// Apply type alias name (e.g., Apply1).
14		$ApplyN:ident,
15		// Brand trait name (e.g., Brand1).
16		$BrandN:ident,
17		// Documentation string for the kind (e.g., "* -> *").
18		$kind_str:literal,
19		// List of generic type parameters (e.g., (A, B)).
20		($($T:ident),+)
21	) => {
22		#[doc = "Trait for [brands][crate::brands] of [types][crate::types] of kind `"]
23		#[doc = stringify!($kind_str)]
24		#[doc = "`."]
25		pub trait $KindN<$($T),+> {
26			type Output;
27		}
28
29		#[doc = "Alias for [types][crate::types] of kind `"]
30		#[doc = stringify!($kind_str)]
31		#[doc = "`."]
32		pub type $ApplyN<Brand, $($T),+> = <Brand as $KindN<$($T),+>>::Output;
33
34		impl<Brand, $($T),+> Kind<($($T,)+)> for Brand
35		where
36			Brand: $KindN<$($T),+>,
37		{
38			type Output = $ApplyN<Brand, $($T),+>;
39		}
40
41		#[doc = "Brand trait for [types][crate::types] with kind `"]
42		#[doc = stringify!($kind_str)]
43		#[doc = "`."]
44		pub trait $BrandN<Concrete, $($T),+>
45		where
46			Self: Kind<($($T,)+)>,
47		{
48			fn inject(a: Concrete) -> Apply<Self, ($($T,)+)>;
49			fn project(a: Apply<Self, ($($T,)+)>) -> Concrete;
50		}
51
52		impl<Me, Concrete, $($T),+> Brand<Concrete, ($($T,)+)> for Me
53		where
54			Me: Kind<($($T,)+)> + $BrandN<Concrete, $($T),+>,
55		{
56			fn inject(a: Concrete) -> Apply<Self, ($($T,)+)> {
57				<Me as $BrandN<Concrete, $($T),+>>::inject(a)
58			}
59
60			fn project(a: Apply<Self, ($($T,)+)>) -> Concrete {
61				<Me as $BrandN<Concrete, $($T),+>>::project(a)
62			}
63		}
64	};
65}
66
67hkt!(Kind1, Apply1, Brand1, "* -> *", (A));
68hkt!(Kind2, Apply2, Brand2, "* -> * -> *", (A, B));
69hkt!(Kind3, Apply3, Brand3, "* -> * -> * -> *", (A, B, C));
70hkt!(Kind4, Apply4, Brand4, "* -> * -> * -> * -> *", (A, B, C, D));