【发布时间】:2021-06-30 19:23:11
【问题描述】:
我有这个有效的功能:
fn compose<A, B, C>(f: impl Fn(A) -> B, g: impl Fn(B) -> C) -> impl Fn(A) -> C {
move |x: A| g(f(x))
}
我想在这种情况下使用柯里化,这样我就可以做到:
/* THIS */
compose(f)(g)(x)
/* Instead of this */
compose(f, g)(x)
考虑制作一个这样的宏是否合理?
compose(f)(g)(h)···(x)
我设法得到了一些与我想要的有点相似的东西:
fn compose<A, B, C, F: 'static, G: 'static>(f: F) -> impl Fn(G) -> Box<dyn Fn(A) -> C>
where
F: Fn(A) -> B + Copy,
G: Fn(B) -> C + Copy,
{
move |g: G| Box::new(move |x: A| g(f(x)))
}
let inc = |x| x + 1;
let mult2 = |x| x * 2;
let inc_compose = compose(inc);
println!("{}", inc_compose(mult2)(3)); // 8
现在有一个新问题:在基于我的compose函数创建高阶函数时,我需要给函数一个依赖于另一个函数的类型:
let inc = |x: usize| x + 1;
let mult2 = |x: usize| x * 2;
let mult3 = |x: usize| x * 3;
let inc_compose = compose(inc);
println!("{}", inc_compose(mult2)(3)); // 8
println!("{}", inc_compose(mult3)(3)); // ERROR: [rustc E0308] [E] mismatched types
有没有办法避免这个错误?
这些类似的帖子都没有回答我的问题:
- How do I emulate Lisp (apply) or (curry) in Rust?
- How to implement a multiple level currying function in Rust?
- How to invoke a multi-argument function without creating a closure?
主要是想通过currying获得做无点编程的能力。
【问题讨论】:
-
docs.rs/partial_application/0.2.1/partial_application 有一个用于部分应用宏的 crate,但实际上没有任何语言支持。
-
您可能对
pipeline感兴趣,这是一个提供pipe!()宏的流行板条箱。 -
问题不在于是否可以使用超过 2 个参数进行组合,这是相当琐碎的,问题是是否可以使用柯里化来完成。
-
我还会提到这个关于使用 return-position impl Trait 进行柯里化的评论线程:internals.rust-lang.org/t/currying-in-rust/10326/2。但是,嵌套的 impl Trait 不可用,所以这样的东西(还)不起作用:play.rust-lang.org/…
-
当 Fn 特征变得稳定时,可以通过编写一个 proc-macro 将函数转换为实现 Fn 的结构,同时为其生成一个 curry() 方法,这样你就可以将其用作 foo(a,b,c) 或 foo.curry()(a)(b)(c)。
标签: rust functional-programming