Итак, я писал (пытался) несколько макросов 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 стремление на данный момент, вряд ли это кажется практичным