How to curry more than one argument?


#1

In Moss, currying is stright forward. Simply change

diffh = |h,f,x| (f(x+h)-f(x-h))/(2*h)

into

diffh = |h| |f| |x| (f(x+h)-f(x-h))/(2*h)

That’s boring, of course. Let’s state the directional derivative:

diffh = |h| |v| |f| |x| (f(x+h*v)-f(x-h*v))/(2*h)

Usage examples you will find here: moss/doc/examples/differential-geometry.

How am I supposed to do this in Rust? It seems we are forced to box the inner closure:

type RtoR = Box<dyn Fn(f64)->f64>;

fn diffh(h: f64) -> impl Fn(RtoR) -> RtoR {
    return move |f: RtoR| -> RtoR {
        return Box::new(move |x| (f(x+h)-f(x-h))/(2.0*h));
    }
}

fn main(){
    let diff = diffh(0.0001);
    let f = diff(Box::new(|x| x.ln()));
    println!("{}",f(1.0));
}

Is it possible to reformulate diffh without dyn? Changing h into a type level constant is assumed to be bogus trait magic.


#2

In theory, “impl everything” could work:

fn diffh(h: f64) -> impl Fn(impl Fn(f64) -> f64) -> impl Fn(f64) -> f64 {
    return move |f| {
        move |x| (f(x+h)-f(x-h))/(2.0*h)
    }
}

but nested impl are not allowed, so… let’s try to be more explicit:

fn diffh<F>(h: f64) -> impl Fn(F) -> impl Fn(f64) -> f64
where F: Fn(f64) -> f64 { ... }

Unfortunately, we learn that:

impl Trait not allowed outside of function and inherent method return types.

I think it’s not an inherent limitation and could be supported in the future. But for now, I think the last dyn has to stay there.

You could work around this issue by making diffh return a concrete struct (instead the first layer of currying).


#3

Ah ok. This leads me to:

struct Diff {h: f64}

impl Diff {
    fn call(&self, f: impl Fn(f64)->f64) -> impl Fn(f64)->f64 {
        let h = self.h;
        return move |x| (f(x+h)-f(x-h))/(2.0*h);
    }
}

fn diffh(h: f64) -> Diff {Diff{h}}


fn main(){
    let diff = diffh(0.0001);
    let f = diff.call(|x| x.ln());
    println!("{}",f(1.0));
}

Now, Diff should just satisfy the Fn bound, for reasons of purity.