1

If I wanted to generate a polynomial function in Rust, one way to do it is the following,

fn new_polynomial(vec: Vec<i32>) -> impl Fn(i32) -> i32 {
    move |x| vec.iter().fold(0, |acc, a| x * acc + a)
}

But, since I want to define lots of higher-order functions (find roots, differentiate, integrate, etc.), I would like to have these functions implemented as methods. The code that I have is as follows,

trait Function {
    fn new_polynomial(vec: Vec<i32>) -> Self;
    fn eval(&self, x: i32) -> i32;
}

impl<F> Function for F
where
    F: Fn(i32) -> i32,
{
    fn new_polynomial(vec: Vec<i32>) -> Self {
        move |x| vec.iter().fold(0, |acc, a| x * acc + a)
    }

    fn eval(&self, x: i32) -> i32 {
        self(x)
    }
}

and produces the following E308,

error[E0308]: mismatched types
  --> src/main.rs:14:9
   |
9  | impl<F> Function for F
   |      - expected this type parameter
...
13 |     fn new_polynomial(vec: Vec<i32>) -> Self {
   |                                         ---- expected `F` because of return type
14 |         move |x| vec.iter().fold(0, |acc, a| x * acc + a)
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `F`, found closure
   |
   = note: expected type parameter `F`
                     found closure `{closure@src/main.rs:14:9: 14:17}`
   = help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `F`

Hopefully I'm not missing something obvious here.

Thanks.

8
  • The new_polynomial function you have defined within the trait Function is not a method. In Rust, methods are specifically associated functions that take a self argument. Commented Oct 9, 2024 at 12:16
  • @jthulhu is it a constructor in that case? I should probably add that I will be implementing actual methods, taking a self argument. Commented Oct 9, 2024 at 12:20
  • Your function always returns the same type, but it promises to return a type of the callers choosing, which might be different types, that doesn't work well together. Commented Oct 9, 2024 at 12:28
  • I’d have a struct Polynomial(Vec<i32>); and put the fold in the implementation of eval for impl Function for Polynomial. Commented Oct 9, 2024 at 12:47
  • @Ry- I could do this, but I found that it's cumbersome and I would like to use this as an opportunity to improve my understanding of closures. Commented Oct 9, 2024 at 12:52

1 Answer 1

1

If you want a method on vectors that converts them to a polynomial, you should implement the trait on the vectors, not on the functions:

trait ToPolynomial {
    fn new_polynomial(self) -> impl Fn(i32) -> i32;
}

impl ToPolynomial for Vec<i32> {
    fn new_polynomial(self) -> impl Fn(i32) -> i32 {
        move |x| self.iter().fold(0, |acc, a| x * acc + a)
    }
}

The Function trait should not contain this method:

trait Function {
    fn eval(&self, x: i32) -> i32;
}

impl<F> Function for F
where
    F: Fn(i32) -> i32,
{
    fn eval(&self, x: i32) -> i32 {
        self(x)
    }
}

You would use these traits like this:

let polynomial = vec![1,2,3].new_polynomial();
println!("{}", polynomial.eval(2));

playground

Sign up to request clarification or add additional context in comments.

4 Comments

This is a good way of doing it, thanks.
With this Function is basically just a different way to spell Fn(i32) -> i32 I would probably omit it completely.
What is the best approach when returning a closure from a function defined in the Function trait here? Return type impl Fn(i32) -> i32 works, but seems clunky, especially since F is already defined as Fn(i32) -> i32. After I changed i32 to be generic, and used floats in a differentiation function, I want to return the generated derivative function.
@JamesBaw Another alternative is to return impl Function, but you can't simply reuse F, as the types will not be right. You will have to be more specific, maybe in a new question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.