Rust macros have hygiene, so this doesn't work:
macro_rules! λ {
($e:expr) => {
|it| $e
}
}
fn main() {
// this looks like it should emit:
// let f = |it| it > 0
// but it's not quite that
let f = λ!(it > 0);
f(42);
}
This doesn't work because of syntax context (there's probably a better link for this) so that the it > 0 in the intended body of the lambda will not actually find the |it| that's being used as the lambda parameter.
This is, usually, what you want. Macro hygiene is a great feature.
However, what if I really want to write an anaphoric macro like this? Does Rust offer a mechanism for doing so, or is the only solution in Rust to require that the macro also provide the ident separately - as in λ!(it, it > 0)?
For this particular case, this is silly since that's longer than the normal lambda to begin with, but this is just an example so bear with me. As an example from a different programming language, Racket has hygiene by default but also provides a syntax-parameter (the aif example in there does this).
You can do this with procedural macros since they are unhygienic.
[package]
name = "mymacros"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
quote = "1.0.36"
syn = { version = "2.0.65", features = ["full"] }
use proc_macro::TokenStream;
use quote::quote;
use syn::Expr;
#[proc_macro]
pub fn λ(item: TokenStream) -> TokenStream {
let expr = syn::parse_macro_input!(item as Expr);
quote! { |it| #expr }.into()
}
[dependencies]
mymacros = { path = "./mymacros" }
use mymacros::λ;
fn main() {
let f = λ!(it > 0);
dbg!(f(42));
}
[src/main.rs:6:5] f(42) = true
However, procedural macros are daunting to get into and can be complicated even for simple things. If you want to continue using declarative macros (i.e. macro_rules!) then there is the unhygienic2 crate that does that for you:
macro_rules! λ {
($e:expr) => {
|it| unhygienic2::unhygienic! { $e }
};
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With