生锈的功能组成链
我想在Rust的对象方法链中实现功能组成。
在此之前,我确认在RUST中实现了功能应用程序“管道”的对象方法链,如下所示:
https://docs.rs/apply/0.2.2/apply/trait/trait.apply.html
trait Pipe: Sized {
fn pipe<F, B>(self, f: F) -> B
where
F: FnOnce(Self) -> B,
{
f(self)
}
}
impl<T> Pipe for T {}
fn main() {
let string = 1.pipe(|x| x * 2).pipe(|x| x + 1).pipe(|x| x.to_string());
println!("{}", string);
}
现在,功能构成守则是 如何在Rust中撰写功能
fn compose<A, B, C, G, F>(f: F, g: G) -> impl Fn(A) -> C
where
F: Fn(A) -> B,
G: Fn(B) -> C,
{
move |x| g(f(x))
}
fn main() {
let multiply_and_add = compose(|x| x * 2, |x| x + 2);
let divide_and_subtract = compose(|x| x / 2, |x| x - 2);
let finally = compose(multiply_and_add, divide_and_subtract);
println!("Result is {}", finally(10));
}
?
let composed_f = (|x| x * 2).compose(|x| x + 1).compose(|x| x.to_string());
适当的代码在“管道”之类的生锈中实现功能组成?
编辑
功能组成宏引用 https://stackoverflow.com/a/a/45792463/113166608
macro_rules! compose {
( $last:expr ) => { $last };
( $head:expr, $($tail:expr), +) => {
compose_two($head, compose!($($tail),+))
};
}
fn compose_two<A, B, C, G, F>(f: F, g: G) -> impl Fn(A) -> C
where
F: Fn(A) -> B,
G: Fn(B) -> C,
{
move |x| g(f(x))
}
fn main() {
let add = |x| x + 2;
let multiply = |x| x * 2;
let divide = |x| x / 2;
let intermediate = compose!(add, multiply, divide);
let subtract = |x| x - 2;
let finally = compose!(intermediate, subtract);
println!("Result is {}", finally(10));
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
直接在封闭式上实施此功能是棘手的,但是我们可以使用代表一个可合并功能的newType使其变得非常简单。这添加了一个步骤,将转换为可合并的功能,然后在最后再次出现,但是结束时很合理(尤其是考虑到其表现力),它不需要拳击或其他巧妙的技巧,并且实现非常容易理解。
因为它与未包装的,嵌套的闭合调用结合起来,因此编译器也很有可能能够优化所有构图调用,并将封闭式互相关闭,甚至可能进入最终的呼叫站点。
像这样使用:
()
phantomdata
成员必须允许实现命名a
和b
,否则它们将被视为未使用。我选择*mut _
,因为这使得a
和b
中的类型不变。您可以用宏来使构图的表达更好:
Implementing this directly on closures is tricky, but we can make it vastly simpler with a newtype that represents a composeable function. This adds a step to convert into a composeable function and then out again at the end, but it winds up being pretty reasonable (especially considering its expressive power), it requires no boxing or other clever tricks, and the implementation is very easy to understand.
Because it winds up with unboxed, nested closure invocations, it is also very likely that the compiler will be able to optimize away all of the composition calls and inline the closures into each other, likely even into the final call site.
Used like so:
(Playground)
The
PhantomData
members are required to allow the implementation to nameA
andB
, otherwise they would be considered unused. I chose*mut _
as this makes the type invariant inA
andB
.You can make the expression of a composition a bit nicer with a macro: