# Passing Expr /Function as input parameter to anther function

I have the below `Julia` code:

``````f(n) = 6n + 2
result = sum(f, 1:6) # or sum(f(n) for n=1:6)
``````

And replicated it in the below `Rust` code:

``````let f = |n| 6 * n + 2;
let result = (1..=6).map(|n| f(n)).fold(0, |acc, ele| acc + ele);
// or let result: i32 = (1..=6).map(|n| f(n)).sum();
``````

Now I want to make a general function for this, so I wrote the below, but looks like passing the input parameters is wrong:

``````fn main() {
println!("result =  {:?}", result(1..=6, |n: T| 6 * n + 2););
}

fn result(r:Range<T>, f: function ()) {
r.map(|n| f(n)).fold(0, |acc, ele| acc + ele);
}
``````

The syntax for a function that takes no parameters and returns nothing is `f: fn()`.

To be more general and support closures that capture values, you would use one of the `Fn`, `FnMut`, or `FnOnce` traits. You want to use the most flexible one that still works how you will be calling it, which would be `FnMut` here. So that parameter would now be `f: impl FnMut()`.

You're actually trying to map, where the function takes a parameter and returns a value, so that would be more like `f: impl FnMut(T) -> T`.

Your result function needs to declare `T` as a type parameter, and add constraints for all the things you're trying to do with it. Apart from the map call, you're also creating a `0` and adding values. So the most direct translation I can make of your code is:

``````extern crate num;
use num::Zero;

fn result<T>(r: Range<T>, mut f: impl FnMut(T) -> T) -> T
where
T: Zero + Add<Output = T>,
Range<T>: Iterator<Item = T>,
{
r.map(|n| f(n)).fold(T::zero(), |acc, ele| acc + ele)
}
``````

You can do this without the `num` crate if you use the `Sum` trait instead of the manual `fold`. The call to `map` can also be simplified in this case, so I'd write it like this:

``````use std::iter::Sum;
use std::ops::Range;

fn result<T: Sum>(r: Range<T>, f: impl FnMut(T) -> T) -> T
where
Range<T>: Iterator<Item = T>,
{
r.map(f).sum()
}
``````
2 Likes

Thanks,

1. As I used `1..=6` I got from the compiler that I've to use `RangeInclusive` instead of `Range`
2. I was in need to remove the `T` from `result(1..=6, |n: T| 6 * n + 2)` as I got compile error for it as `^ not found in this scope`

I don't see a need to specify `Range<T>` (or `RangeInclusive<T>`) here - just specify the `r` param as `impl Iterator<Item = T>`.

1 Like

Thanks @cuviper and @vitalyd

If I used `float` in `(1..=6, |n| 6 * n + 2)`then everything is destroyed, I tried using `(1..=6, |n| 6.5 * n as f32 + 2.0)` but did not work!

You'd need something like the following if you want to change the type you iterate over vs what you sum and return:

``````fn result<T, R: Sum>(r: impl Iterator<Item = T>, f: impl FnMut(T) -> R) -> R {
r.map(f).sum()
}
// or (same thing, just different syntax)
fn result<I: Iterator, R: Sum>(r: I, f: impl FnMut(I::Item) -> R) -> R {
r.map(f).sum()
}
``````
1 Like

Thanks @vitalyd I liked the second approach:

``````use std::iter::Sum;

fn main() {
println!("result =  {:?}", result(1..=6, |n| 6 * n + 2));
}

fn result<I: Iterator, R: Sum>(r: I, f: impl FnMut(I::Item) -> R) -> R {
r.map(f).sum()
}
``````

I can understand the main function in returning a sum as R, but did not get why f also return R also! appreciate if you explain little more, thanks

You're basically creating a processing pipeline here, starting with items of type `T` and ending in `R`. `f` is your mapping function - it translates (maps) each `T` to `R`, and then you run the sum over all the resulting `R`s. Does that help/make sense? Or did I miss the thrust of your question?

By default, `Sum` takes the same type as an input, but it can be parameterized too. So you could be a little more generic like:

``````fn result<I: Iterator, T, R: Sum<T>>(r: I, f: impl FnMut(I::Item) -> T) -> R {
r.map(f).sum()
}
``````

So we have `I::Item` mapped to `T` and summed as `R`.

The primitive types in the standard library only implement `Sum<Self>` and `Sum<&Self>`, but other types can do more. For instance, `num-bigint`'s types can `Sum` any integer input.

2 Likes

Turtles all the way down ... 3 Likes

All of these are valid Moss:

``````result = (1..6).sum(|n| 6*n+2)

f = |n| 6*n+2
result = (1..6).map(f).reduce(0,|x,y| x+y)

result = (1..).map(|n| 6*n+2).take(6).sum()

result = (6*n+2 for n in 1..6).sum()

result = (6*n+2 for n in 1..).take(6).sum()
``````

As a general function:

``````result = |r,f,zero=0| r.map(f).reduce(zero,|x,y| x+y)
``````

Moss is already oxidated. And soon it might be moisted too.

Then nothing will prevent me from feeding the dragon, disgracing everybody down to earth.

But feeding dragons before you need to is already flawed. It takes an amount of time before they come out of their dark holes.