Можете ли вы написать анафорический макрос на Rust?

Макросы Rust имеют гигиену, поэтому это не работает:

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);
}

Это не работает из-за синтаксического контекста (вероятно, для этого есть лучшая ссылка), так что it > 0 в предполагаемом теле лямбды фактически не найдет |it|, который используется в качестве параметра лямбды.

Обычно это то, что вы хотите. Макрогигиена — отличная функция.

Однако что, если я действительно хочу написать такой анафорический макрос? Предлагает ли Rust механизм для этого, или единственное решение в Rust требует, чтобы макрос также предоставлял ident отдельно - как в λ!(it, it > 0)?

В данном конкретном случае это глупо, поскольку изначально это длиннее, чем обычная лямбда, но это всего лишь пример, так что терпите меня. В качестве примера другого языка программирования, Racket по умолчанию имеет гигиену, но также предоставляет синтаксический параметр (пример aif делает это).

Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
2
0
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Сделать это можно с помощью процедурных макросов, поскольку они негигиеничны.

макро ящик

[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

Однако процедурные макросы сложны для понимания и могут оказаться сложными даже для простых вещей. Если вы хотите продолжать использовать декларативные макросы (т.е. macro_rules!), то есть контейнер unhygienic2, который сделает это за вас:

macro_rules! λ {
    ($e:expr) => {
        |it| unhygienic2::unhygienic! { $e }
    };
}

Другие вопросы по теме