Частичный прикладной макрос в Rust, работает, но - PullRequest
0 голосов
/ 21 июня 2020

Итак, я писал (пытался) несколько макросов Variadi c, чтобы попытаться реализовать compose и curry в ржавчине. pipe было достаточно просто. Variadi c частичное применение правда? Не так много. Реквизит всем, кто может придумать решение для этого частичного макроса приложения, в котором не используются эти надоедливые, казалось бы, игнорируемые аргументы типа (и, возможно, варианты c? Без отражения, я думаю, это невозможно):

    //ltr compose for closures
macro_rules! pipe {
    ($init:tt |> $($fn:ident),+) => {{
        let mut r = $init;
        $( r = $fn(r); )*
        r
    }}
}

//partially apply a closure w/ up to 4 args
macro_rules! apply {
    ($fn:ident<$t1:ty,$t2:ty>($arg1:expr)) => {
        |x:$t2| $fn($arg1 as $t1, x)
    };
    ($fn:ident<$t1:ty,$t2:ty,$t3:ty>($arg1:expr)) => {
        |x:$t2, y:$t3| $fn($arg1 as $t1,x, y)
    };
    ($fn:ident<$t1:ty,$t2:ty,$t3:ty>($arg1:expr, $arg2:expr)) => {
        |x:$t3| $fn($arg1 as $t1,$arg2 as $t2,x)
    };
    ($fn:ident<$t1:ty,$t2:ty,$t3:ty,$t4:ty>($arg1:expr)) => {
        |x: $t2, y:$t3, z:$t4| $fn($arg1 as $t1, x, y, z)
    };
    ($fn:ident<$t1:ty,$t2:ty,$t3:ty,$t4:ty>($arg1:expr, $arg2:expr)) => {
        |x:$t3, y:$t4| $fn($arg1 as $t1,$arg2 as $t2, x, y)
    };
    ($fn:ident<$t1:ty,$t2:ty,$t3:ty,$t4:ty>($arg1:expr, $arg2:expr, $arg3:expr)) => {
        |x:$t4| $fn($arg1 as $t1,$arg2 as $t2,arg3 as $t3,x)
    };
}

fn main() {
    
 
    let add = |x:i32, y:i32| x + y;
    let sq = |x:i32| x * x;
    let dbl = |x:i32| x * 2;
    //blargh i hate those typeargs! i need them for the matcher
    //to get the original params number and type since rust has no reflection :(
    //weirdly if i ignore them with _ it works. But it will luckily fail
    //hard if you supply incorrect args.
    let plus1 = apply!(add<_,_>(1));
    
    let r = pipe!(3 |> dbl, plus1, sq);
    
    print!("{}", r);
}

Edit: Причина, по которой я, похоже, не могу использовать варианты c args для этого, заключается в том, что это меняет структуру закрытия. На первый взгляд это выглядело хорошо, я бы просто заключил его в оператор match, основанный на общих параметрах и разнице между количеством выражений и общими параметрами. но если вы попытаетесь вернуть закрытие различных подписей в руке матча, он не будет компилироваться. Хорошая новость в том, что этот подход, вероятно, требует минимальных затрат. Но на самом деле это не большое улучшение по сравнению с частичным применением через встроенные закрытия по мере необходимости:

//simple, works, no type args or even type declarations on params I'm just a crazy person who wants it all!
let add = |x, y| x + y;
let add1 = |x| add(x, 1);

Так что это действительно просто академическое c стремление на данный момент, вряд ли это кажется практичным

1 Ответ

0 голосов
/ 05 июля 2020

Я не уверен, понимаю ли я ваш вопрос, но я думаю, что, возможно, эта библиотека может вам помочь: https://docs.rs/partial_application/0.2.0/partial_application/

#[macro_use]
extern crate partial_application;

//ltr compose for closures
macro_rules! pipe {
    ($init:tt |> $($fn:ident),+) => {{
        let mut r = $init;
        $( r = $fn(r); )*
        r
    }}
}

fn main() {


    let add = |x:i32, y:i32| x + y;
    let sq = |x:i32| x * x;
    let dbl = |x:i32| x * 2;
    //blargh i hate those typeargs! i need them for the matcher
    //to get the original params number and type since rust has no reflection :(
    //weirdly if i ignore them with _ it works. But it will luckily fail
    //hard if you supply incorrect args.
    let plus1 = partial!(add => 1,_);
    let r = pipe!(3 |> dbl, plus1, sq);

    print!("{}", r);
}

Вы можете обратиться к этой библиотеке создайте свой собственный макрос.

...