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}