首页 > 解决方案 > Rust 中的部分应用程序宏,工作但

问题描述

所以我正在编写(尝试)一些可变参数宏来尝试在 rust 中实现 compose 和 curry。pipe很容易。可变的部分应用虽然?没那么多。任何人都可以为这个不使用那些看似可忽略的讨厌的类型 args 的部分应用程序宏提出解决方案的人的道具(也许是可变参数?没有反射,我认为这是不可能的):

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

编辑:我似乎不能对此做可变参数的原因是因为它改变了闭包的结构。乍一看似乎很好,我只是根据总参数和 expr 与总参数之间的差异将它包装在匹配语句中。但是如果您尝试在匹配臂中返回不同签名的闭包,它将无法编译。好消息是这种方法的开销可能很低。但它确实不是通过必要时通过内联闭包进行部分应用程序的很大改进:

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

所以在这一点上它真的只是一个学术追求,它似乎并不实用

标签: rustmacroscurryingpartial-application

解决方案


我不确定我是否理解你的问题,但我认为这个库可能会对你有所帮助: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);
}

你可以参考这个库来创建你自己的宏。


推荐阅读