Car*_*mez 7 functional-programming rust
我有这个有效的功能:
\nfn compose<A, B, C>(f: impl Fn(A) -> B, g: impl Fn(B) -> C) -> impl Fn(A) -> C {\n move |x: A| g(f(x))\n}\nRun Code Online (Sandbox Code Playgroud)\n我想在这种情况下使用柯里化,这样我就可以这样做:
\n/* THIS */\ncompose(f)(g)(x)\n\n/* Instead of this */\ncompose(f, g)(x)\nRun Code Online (Sandbox Code Playgroud)\n考虑制作一个宏来实现这一点是否合理?
\ncompose(f)(g)(h)\xc2\xb7\xc2\xb7\xc2\xb7(x)\nRun Code Online (Sandbox Code Playgroud)\n我已经设法得到与我想要的有点相似的东西:
\nfn compose<A, B, C, F: \'static, G: \'static>(f: F) -> impl Fn(G) -> Box<dyn Fn(A) -> C>\nwhere\n F: Fn(A) -> B + Copy,\n G: Fn(B) -> C + Copy,\n{\n move |g: G| Box::new(move |x: A| g(f(x)))\n}\n\nlet inc = |x| x + 1;\nlet mult2 = |x| x * 2;\n\nlet inc_compose = compose(inc);\n\nprintln!("{}", inc_compose(mult2)(3)); // 8\nRun Code Online (Sandbox Code Playgroud)\n现在有一个新问题:当基于我的函数创建高阶函数时compose,我需要为该函数提供依赖于另一个函数的类型:
let inc = |x: usize| x + 1;\nlet mult2 = |x: usize| x * 2;\nlet mult3 = |x: usize| x * 3;\n\nlet inc_compose = compose(inc);\n\nprintln!("{}", inc_compose(mult2)(3)); // 8\n\nprintln!("{}", inc_compose(mult3)(3)); // ERROR: [rustc E0308] [E] mismatched types\nRun Code Online (Sandbox Code Playgroud)\n有没有办法避免这个错误?
\n这些类似的帖子都没有回答我的问题:
\n\n主要原因是我希望柯里化能够获得无点编程的能力。
\n在 Rust 中,柯里化是很困难的。当您尝试时,严格的类型系统、生命周期和impl不存在的嵌套特征都会破坏您的一天。然而,可以创建一个宏来柯里化函数,我曾经在代码高尔夫中这样做过。非高尔夫版本在这里:
macro_rules! curry{
(
$f:ident
$(
($args:ident : $types:ty)
)*
) => {
$(move |$args: $types|)*
$f(
$($args),*
)
}
}
Run Code Online (Sandbox Code Playgroud)
它匹配表单的表达式并返回导致函数调用的闭包name(arg1, type1)(arg2, type2)...(argN, typeN)链。move然而,大多数时候,您可以只使用_类型并让推理来解决它。使用它compose很简单:
let inc = |x| x as u32 + 1;
let double = |x| x * 2;
let curried = curry!(compose(f: _)(g: _));
assert_eq!(curried(inc)(double)(7), 16);
Run Code Online (Sandbox Code Playgroud)
在本例中,宏生成的代码如下所示:
move |f: _| move |g: _| compose(f, g)
Run Code Online (Sandbox Code Playgroud)
它只是获取提供的名称和类型并将其粘贴到闭包头中,因此您可以使用它来将泛型函数的参数强制转换为具体类型。 操场