Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Rust: Apply function n times

The problem

I want to create a function (chain) that takes a function f: Fn(i32) -> i32, number n and returns a new function g: Fn(i32) -> i32 that applys f to it’s input n times.

For example: chain(3, f) should return a function eqvivalent to: |x| f(f(f(x))).

Here is my attempt at achieving this (similar code works in Python):

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

fn chain(n: i32, f: Box<dyn Fn(i32) -> i32>) -> Box<dyn Fn(i32) -> i32> {
    println!("This is not printed when the resulting function is called!");
    match n {
        1 => f,
        _ if n > 1 => {
            let g = chain(n - 1, f);
            Box::new(move |x| g(f(x)))
        },
        _ => Box::new(|x| x),
    }
}

The compiler produces some errors about borrowing moved values, and I can’t figure out how to fix them.

error[E0382]: use of moved value: `f`
 --> src/lib.rs:7:22
  |
1 | fn chain(n: i32, f: Box<dyn Fn(i32) -> i32>) -> Box<dyn Fn(i32) -> i32> {
  |                  - move occurs because `f` has type `Box<dyn Fn(i32) -> i32>`, which does not implement the `Copy` trait
...
6 |             let g = chain(n - 1, f);
  |                                  - value moved here
7 |             Box::new(move |x| g(f(x)))
  |                      ^^^^^^^^   - use occurs due to use in closure
  |                      |
  |                      value used here after move

Background

I want to create a program that takes an arithmetic expression in string form and then creates a function that can evaluate the expression. For example: "2*x+3" should result in a function |x| add(mul(2,x),3). The resulting function is called many times and should execute as fast as possible.

>Solution :

You use f twice. You cannot. You cannot use a reference either, since the function is local and you cannot return a reference to it.

The simplest fix is to replace Box with Rc:

fn chain(n: i32, f: Rc<dyn Fn(i32) -> i32>) -> Rc<dyn Fn(i32) -> i32> {
    println!("This is not printed when the resulting function is called!");
    match n {
        1 => f,
        _ if n > 1 => {
            let g = chain(n - 1, Rc::clone(&f));
            Rc::new(move |x| g(f(x)))
        },
        _ => Rc::new(|x| x),
    }
}

However, this incurs an overhead of a dynamic function call for each operation, an I think a simple match to the operation will be faster.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading