Finn
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.
1 Like
krdln
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).
Finn
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.