lambda_types/macros.rs
1
2
3#[macro_export]
4/**
5 Helper macro for easily defining types that implement [`crate::Function`].
6
7 ## Syntax
8 The body of the macro should contain an arbitrary amount of "function type" items, ending in semicolons.
9
10 These "function type" items may have an arbitrary amount of attributes.
11
12 Due to how the macro is implemented, `cfg` attributes must be specified _with a @ instead of #_, like this:
13 `@[cfg(feature = "abc")]`
14
15 The body of one of these items is as follows:
16 ```text
17 pub fn Name<A, B> ::= { C. D. { A, B {C, D}}}
18 where A: B, {A, B}: {C, D}, /* ... */;
19 ```
20 It's quite a bit to take in, but it's actually quite simple! Let's break it down.
21
22 - The visibility specifier `pub` is optional, defaulting to private, as expected of any other item.
23
24 - The `Name` is the name of the type that's publicly exported by the macro.
25 As you can see, type parameters are also supported, but const generics are unfortunately not.
26
27 - Following the `::=` is the actual definition enclosed in `{}` braces.
28 Everything within the brackets is implicitly passed to `crate::call`.
29
30 - The `where` clauses are an unfortunate consequence of using a declarative macro instead of a procedural one,
31 as the macro can't generate one _for_ us due to the inability to use macro calls as parameter guards.
32 Both sides of each clause are implicitly passed to `crate::call`.
33
34 In order for the compiler to accept your function, you must tell the compiler in these clauses
35 that all arguments used in the definition are actually _able_ to be used in the way they're used.
36
37 A good strategy is to write each call out in the where clause while you're writing, like this:
38 ```text
39 fn F ::= { A. B. C. { C, {B, A}, C }} where
40 B: A, // B calls A
41 C: {B, A}, // C calls {B, A}
42 {C, {B, A}}: C; // {C, {B, A}} calls C
43 ```
44
45 Unfortunately, due to implementation complexity, anonymous functions like this:
46 ```text
47 // λn.λf.λx. n (λg.λh. h (g f)) (λu.x) (λu.u)
48 pub fn Predecessor ::= { N. F. X. { N {G. H. H { G, F }}, Constant<X>, Identity } };
49 ```
50 are unsupported.
51 Instead, you can break it up into smaller definitions, like this:
52 ```text
53 pub fn Predecessor ::= { N. F. X. { N, Pred_1<F>, Constant<X>, Identity } };
54 fn Pred_1<F> ::= { G. H. { H { G, F } } };
55 ```
56 which is actually the definition used in [`crate::math::Predecessor`], sans the `where` clauses.
57
58 Reading through how the crate defines function types is highly recommended to get a grasp on the syntax!
59
60 This macro is **hygienic**.
61
62 */
63macro_rules! define {
64 (
65 $(
66 $(#[$meta: meta])*
67 $(@[$modmeta: meta])*
68 $vis: vis fn $identifier: ident
69 $(< $($typearg: ident),+ >)?
70 ::= { $($definition: tt)+ }
71 $(where $($lhs: tt : $rhs: tt),+ $(,)?)?
72 ;
73 )*
74 ) => {::paste::paste! {
75 $(
76 #[allow(non_snake_case)]
77 $(#[$modmeta])*
78 mod [< __$identifier >] {
79 #![allow(unused_parens, non_camel_case_types, unused_imports)]
80 use super::*;
81
82 $crate::define!{ @item $(#[$meta])* $identifier ; $($($typearg)+)? }
83 $crate::define!{
84 @impl $identifier; $($($typearg)+)? ;
85 { $($definition)+ }
86 $(where $($lhs: $rhs),+)?
87 }
88 }
89 $(#[$modmeta])*
90 $vis use [< __$identifier >]::$identifier;
91 )*
92 }};
93 (
94 @item $(#[$meta: meta])* $name: ident ; $($($typearg: ident)+)?
95 ) => {
96 $(#[$meta])*
97 #[allow(unused_parens)]
98 #[allow(non_camel_case_types)]
99 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
100 pub struct $name $( < $($typearg),+ > )? {
101 _p: ::core::marker::PhantomData<($($($typearg,)+)?)>
102 }
103 };
104 (
105 @impl $ident: ident ; $($arg: ident)*;
106 { $name: ident . $name2: ident . $($definition: tt)+ } $(where $($lhs: tt:$rhs: tt),+)?
107 ) => { ::paste::paste! {
108 #[allow(non_camel_case_types)]
109 impl<$($arg, )* $name> $crate::Function<$name> for $ident < $($arg,)* > {
110 type Output = [< $ident __ $name >] <$($arg,)* $name>;
111 }
112 $crate::define! {
113 @item #[doc(hidden)] [< $ident __ $name >] ; $($arg)* $name
114 }
115 $crate::define! {
116 @impl [<$ident __ $name>] ; $($arg)* $name;
117 { $name2 . $($definition)+ } $(where $($lhs : $rhs),+)?
118 }
119 } };
120 (
121 @impl $ident: ident ; $($args: ident)*;
122 { $name: ident . $definition: tt } $(where $($lhs: tt:$rhs: tt),+)?
123 ) => {
124 #[allow(non_camel_case_types)]
125 impl<$($args, )* $name> $crate::Function<$name> for $ident <$($args, )*>
126 $(
127 where
128 $(
129 $crate::call!($lhs) : $crate::Function<$crate::call!($rhs)>
130 ),+
131 )?
132 {
133 type Output = $crate::call!{ $definition };
134 }
135 };
136}
137
138/**
139 Ergonomic wrapper macro for calling a function.
140
141 Calling syntax is modeled around the lambda calculus, where:
142 - `fx` is translated to `f, x`
143 - `f(...)` is translated to `f, {...}`
144
145 So, for example, `ab(c(de)f)gh` translates to `a, b, { c, { d, e }, f }, g, h`.
146
147 The whitespace isn't mandatory, but is recommended for readibility (see: `a,b{c,{d,e},f},g,h`).
148
149 This macro is **hygienic**.
150 */
151#[macro_export]
152macro_rules! call {
153 ({$($wrapped: tt)+}) => { $crate::call!($($wrapped)+) };
154 ($name: ty) => { $name };
155 ($name: ty , $arg: ty) => {
156 <$name as $crate::Function<$arg>>::Output
157 };
158 ($name: ty , { $($arg: tt)+ } $($arg2: tt)*) => {
159 $crate::call!( $crate::call!($name , $crate::call!($($arg)+) ) $($arg2)* )
160 };
161 ($name: ty , $arg: ty , $($arg2: tt)+) => {
162 $crate::call!( $crate::call!($name , $arg), $($arg2)+ )
163 };
164}
165
166/**
167 Chains applications of a function onto many arguments.
168
169 For example, `chained!(Composed with A, B, C, D)` expands to `Composed<A, Composed<B, Composed<C, D>>>`.
170
171 This macro is **hygienic**.
172 */
173#[macro_export]
174macro_rules! chained {
175 ($name: ident with $lhs: ty, $rhs: ty $(, $extra: ty)+) => {
176 $name<$lhs, $crate::chained!($name with $rhs $(, $extra)+)>
177 };
178 ($name: ident with $lhs: ty, $rhs: ty) => {
179 $name<$lhs, $rhs>
180 }
181}