Type aliases for closures - closures

I would've thought the following code would work:
use std::num::{Num};
use std::fmt::{Show};
pub type GradFn<T : Num> = for<'a> fn(&'a [T]) -> (T, Vec<T>);
fn minimize<T : Show, F>(f : GradFn<T>, x0 : &[T]) {
// some no-op to test types
print!("{}",f(x0))
}
fn main() {
let xSquared : GradFn<f64> = |x : &[f64]| -> (f64, Vec<f64>) {
return (x[0] * x[0], vec![2.0 * x[0]]);
};
let (fx, grad) = xSquared(vec![2.0f64].as_slice());
print!("{}", fx);
}
But I'm getting a compiler error (see here):
<anon>:12:32: 14:4 error: mismatched types: expected `fn(&'a [f64]) -> (f64, collections::vec::Vec<f64>)`, found `|&[f64]| -> (f64, collections::vec::Vec<f64>)` (expected extern fn, found fn)
<anon>:12 let xSquared : GradFn<f64> = |x : &[f64]| -> (f64, Vec<f64>) {
<anon>:13 return (x[0] * x[0], vec![2.0 * x[0]]);
<anon>:14 };

fn does not define a closure type; it defines bare function pointers (i.e. pointers to functions defined with the fn keyword). That's why you can't assign a closure to a GradFn. Instead, you want to use either Fn, FnMut or FnOnce.
There are a few more changes I needed to make to get this code to compile:
On minimize, the f parameter as you wrote it receives an unsized type by value, which is forbidden. You also put an F type parameter that you don't use. You probably meant to constrain F and to use F as the type of f.
The compiler won't let us use a type alias in a type parameter constraint; we need to spell out the trait fully. This means the type alias is basically useless.
I removed the type annotation on xSquared, which is unnecessary. This let me remove the type alias completely.
Here's the final code:
#![feature(unboxed_closures)]
use std::num::{Num};
use std::fmt::{Show};
fn minimize<T: Show, F: FnMut(&[T]) -> (T, Vec<T>)>(mut f: F, x0: &[T]) {
// some no-op to test types
print!("{}", f(x0))
}
fn main() {
let xSquared = |x: &[f64]| -> (f64, Vec<f64>) {
return (x[0] * x[0], vec![2.0 * x[0]]);
};
let (fx, grad) = xSquared(vec![2.0f64].as_slice());
print!("{}", fx);
}

If your GradFn is actually going to be a bare function pointer (as opposed to a closure) you can keep the type alias, like this:
use std::num::Num;
use std::fmt::Show;
// this type has to point to a bare function, not a closure
pub type GradFn<T> = for<'a> fn(&'a [T]) -> (T, Vec<T>);
fn minimize<T>(f : GradFn<T>, x0 : &[T])
where T: Show + Num {
// some no-op to test types
println!("{}",f(x0))
}
fn main() {
// this is now a bare function
fn x_squared(x : &[f64]) -> (f64, Vec<f64>) {
return (x[0] * x[0], vec![2.0 * x[0]]);
}
// and this is a pointer to it, that uses your type alias
let x_sq : GradFn<f64> = x_squared;
let (fx, grad) = x_sq(&[2f64]);
println!("fx: {} - grad: {}", fx, grad);
minimize(x_sq, &[3f64]);; // works with minimize as well
}

Related

Simplify SRTP resolved on return type

I have some production code that I'd like to simplify (especially in light of new SRTP F# behaviour).
The intention is to statically resolve a method/function based solely on the return type required.
A simplified version of it is this:
type TypeOf<'a> = T
type ZeroFactory = Z with
static member Zero(_: ZeroFactory,_ : TypeOf<int>) : _ = 0
static member Zero(_: ZeroFactory,_ : TypeOf<string>) : _ = ""
let inline inlineZero t =
((^T or ^N) : (static member Zero : ^T * TypeOf< ^N > -> ^N)
(t, T))
let inline zero () = inlineZero Z
let foo : int = zero ()
let bar : string = zero ()
this code compiles and does what I intend, but has always felt overly contrived.
I CAN write this:
let inline inlineZero2 t =
(^T : (static member Zero : ^T * TypeOf< ^N > -> ^N)
(t, T))
and to my eyes, that would seem to be good enough, but if i write:
let inline zero2 () = inlineZero2 Z
I get
Error FS0043 A unique overload for method 'Zero' could not be determined based on type information prior to this program point. A type annotation may be needed.
Known return type: 'a
Known type parameters: < ZeroFactory , TypeOf<'a> >
Candidates:
- static member ZeroFactory.Zero: ZeroFactory * TypeOf<int> -> int
- static member ZeroFactory.Zero: ZeroFactory * TypeOf<string> ->
my hunch is that all the static type parameters in the method specification have to be mentioned on the left.

How does one create a struct that holds a type parameterized function in Rust?

I am a beginner in Rust and am trying to create a Parser Combinator library in order to learn the ropes of the language. Very early on in this project I've gotten stuck. I want to have a Parser struct that holds the function used to parse data. Here is my attempt at implementing this.
struct Parser<I, O> {
parse: impl Fn(&Vec<I>) -> Option<(&Vec<I>, O)>
}
Unfortunately, as the compiler informs me, i can not use the "impl Trait" notation in this way. Another way I've tried is by defining a separate type variable for the type of the function itself, as below.
struct Parser<I, O, F>
where
F: impl Fn(&Vec<I>) -> Option<(&Vec<I>, O)>
{
parse: F
}
However, it seems redundant and unnecessary to have to provide the input, output, and function type, as the function type can be derived from the input and output. Also, the compiler gives me an error due to the fact that neither I or O are used.
I also considered Parser may have to be a trait rather than a struct. However I can't really wrap my head around what that would look like, and it seems like you would run into the same issue trying to define a struct that implemented the Parser trait.
Not a lot of context, but you I'll try doing it this way:
struct Parser<I, O> {
parse: Box<dyn Fn(&Vec<I>) -> Option<(&Vec<I>, O)>>,
}
fn main() {
let parser = Parser {
parse: Box::new(|x| {
Some((x, x.iter().sum::<i32>()))
})
};
let v = vec![1, 2, 3, 4];
let result = (parser.parse)(&v).unwrap();
println!("{:?}", result);
}
For some more suggestion I would look here: How do I store a closure in a struct in Rust?
I think all you need is std::marker::PhantomData to silence the error about unused generics. You can also make the code a bit more DRY with some type aliases. (I've replaced &Vec<I> with &[I] as the latter is a strict superset of the former.)
use std::marker::PhantomData;
type Input<'a,I> = &'a [I];
type Output<'a,I,O> = Option<(&'a [I], O)>;
struct Parser<I, O, F>
where
F: Fn(Input<'_,I>) -> Output<'_, I, O>,
{
parse: F,
_phantom: PhantomData<(I, O)>,
}
impl<I, O, F> Parser<I, O, F>
where
F: Fn(Input<'_, I>) -> Output<'_, I, O>,
{
fn new(parse: F) -> Self {
Self {
parse,
_phantom: PhantomData,
}
}
fn parse_it<'a>(&'a self, input: Input<'a, I>) -> Output<'a, I, O> {
(self.parse)(input)
}
}
fn main() {
let parser = Parser::new(|v: &[i32]| Some((v, v.iter().fold(0, |acc, x| acc + x))));
println!("{:?}", parser.parse_it(&[1, 2, 3]));
// ^ Some(([1, 2, 3], 6))
}

Passing a closure that modifies its environment to a function in Rust

I have a closure that captures and modifies its environment. I want to pass this closure to a function that accepts closures:
fn main() {
let mut integer = 5;
let mut closure_variable = || -> i32 {
integer += 1;
integer
};
execute_closure(&mut closure_variable);
}
fn execute_closure(closure_argument: &mut Fn() -> i32) {
let result = closure_argument();
println!("Result of closure: {}", result);
}
Because the closure modifies its environment, this fails:
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
--> src/main.rs:3:32
|
3 | let mut closure_variable = || -> i32 {
| ________________________________^
4 | | integer += 1;
5 | | integer
6 | | };
| |_____^
7 | execute_closure(&mut closure_variable);
| --------------------- the requirement to implement `Fn` derives from here
|
note: closure is `FnMut` because it mutates the variable `integer` here
--> src/main.rs:4:9
|
4 | integer += 1;
| ^^^^^^^
As I understand from When does a closure implement Fn, FnMut and FnOnce?, this means that my closure actually is expanded to a struct that implements the trait FnMut. This trait is mutable, meaning calling the function changes the (implicit) object. I think this correct, because the variable integer should be modified after calling execute_closure().
How do I convince the compiler this is okay and that I actually want to call a FnMut function? Or is there something fundamentally wrong with how I use Rust in this example?
If you can change the function that accepts the closure...
Accept a FnMut instead of a Fn:
fn main() {
let mut integer = 5;
execute_closure(|| {
integer += 1;
integer
});
}
fn execute_closure<F>(mut closure_argument: F)
where
F: FnMut() -> i32,
{
let result = closure_argument();
println!("Result of closure: {}", result);
}
If you can not change the function that accepts the closure...
Use interior mutability provided by types like Cell or RefCell:
use std::cell::Cell;
fn main() {
let integer = Cell::new(5);
execute_closure(|| {
integer.set(integer.get() + 1);
integer.get()
});
}
fn execute_closure<F>(closure_argument: F)
where
F: Fn() -> i32,
{
let result = closure_argument();
println!("Result of closure: {}", result);
}
Or is there something fundamentally wrong with how I use Rust in this example?
Perhaps. An argument of type &mut Fn() -> i32 cannot mutate the variables it has closed over, so the error message makes sense to me.
It's kind of similar to the type &mut &u8 — you could alter the outer reference to point to another immutable reference, but you cannot "ignore" the inner immutability and change the numeric value.
Aside:
The original code uses dynamic dispatch because there is a trait object that provides indirection. In many cases you'd see this version that I posted above, which uses static dispatch and can be monomorphized. I've also inlined the closure as that's the normal syntax.
Here's the original version with just enough changes to work:
fn main() {
let mut integer = 5;
let mut closure_variable = || -> i32 {
integer += 1;
integer
};
execute_closure(&mut closure_variable);
}
fn execute_closure(closure_argument: &mut FnMut() -> i32) {
let result = closure_argument();
println!("Result of closure: {}", result);
}

Implement trait for closure type alias

I have this closure type alias:
type ClosureType = Box<Fn(i32) -> i32>;
this trait:
trait Trait {
fn change(&self, y: i32) -> i32;
}
and these functions:
fn with_one(x: Box<Fn(i32) -> i32>) -> i32 {
x(1)
}
fn plus_one(x: i32) -> i32 {
x+1
}
fn main() {
let a = Box::new(|x: i32|{x+1});
let b: ClosureType = Box::new(|x: i32|{x+1});
let c = Box::new(plus_one);
let d: ClosureType = Box::new(plus_one);
println!("{}", a.change(1));
println!("{}", b.change(1));
println!("{}", c.change(1));
println!("{}", d.change(1));
println!("{}", with_one(a));
println!("{}", with_one(b));
println!("{}", with_one(c));
println!("{}", with_one(d));
}
When I implement the trait Trait for ClosureType or for Box<Fn(i32) -> i32> which is the same if I understand correctly type aliases:
impl Trait for ClosureType {
fn change(&self, y: i32) -> i32{
self(y)
}
}
or
impl Trait for Box<Fn(i32) -> i32> {
fn change(&self, y: i32) -> i32{
self(y)
}
}
for variable a I get:
<anon>:32:22: 32:31 error: no method named `change` found for type
`Box<[closure <anon>:28:22: 28:35]>` in the current scope
<anon>:32 println!("{}", a.change(1));
and for variable c I get:
<anon>:34:22: 34:31 error: no method named `change` found for type
`Box<fn(i32) -> i32 {plus_one}>` in the current scope
<anon>:34 println!("{}", c.change(1));
However variables a and c are accepted from function with_one(x: Box<Fn(i32) -> i32>) -> i32, in other words it seems that they have the same type(Box<Fn(i32) -> i32>) for function with_one but different(Box<[closure <anon>:24:22: 24:35]> and Box<fn(i32) -> i32 {plus_one}) for Trait implementation.
I feel I missing something here but not sure what it is, could you enlighten me?
you can find all the code in this rust playground.
I believe this happens due to automatic coercion (that is, its absence) from a concrete type to a trait object type.
When you call with_one(), the compiler is able to understand from the function argument type that you want a trait object and so it inserts automatic coercions:
with_one(a as Box<Fn(i32) -> i32>);
with_one(c as Box<Fn(i32) -> i32>);
For b and d these coercions have already happened at their assignment place in lets.
For trait methods, however, the compiler does not perform coercions. This is a common behavior around generics (and traits are implemented over generics - their Self type is essentially an implicit type parameter for all trait methods). For example, Rust also does not perform deref coercions when using generics:
trait MyStringLike {}
impl<'a> MyStringLike for &'a str {}
fn function<T: MyStringLike>(t: T) {}
let s: String = "abcde".into();
function(&s); // the trait `main::MyStringLike` is not implemented for the type `&collections::string::String`

Conflicting lifetime requirements when storing closure capturing returned value

EDIT:
I'm trying to create a vector of closures inside a function, add a standard closure to the vector, and then return the vector from the function. I'm getting an error about conflicting lifetimes.
Code can be executed here.
fn vec_with_closure<'a, T>(f: Box<FnMut(T) + 'a>) -> Vec<Box<FnMut(T) + 'a>>
{
let mut v = Vec::<Box<FnMut(T)>>::new();
v.push(Box::new(|&mut: t: T| {
f(t);
}));
v
}
fn main() {
let v = vec_with_closure(Box::new(|t: usize| {
println!("{}", t);
}));
for c in v.iter_mut() {
c(10);
}
}
EDIT 2:
Using Rc<RefCell<...>> together with move || and the Fn() trait as opposed to the FnMut()m as suggested by Shepmaster, helped me produce a working version of the above code. Rust playpen version here.
Here's my understanding of the problem, slightly slimmed down:
fn filter<F>(&mut self, f: F) -> Keeper
where F: Fn() -> bool + 'static //'
{
let mut k = Keeper::new();
self.subscribe(|| {
if f() { k.publish() }
});
k
}
In this method, f is a value that has been passed in by-value, which means that filter owns it. Then, we create another closure that captures f by-reference. We are then trying to save that closure somewhere, so all the references in the closure need to outlive the lifetime of our struct (I picked 'static for convenience).
However, f only lives until the end of the method, so it definitely won't live long enough. We need to make the closure own f. It would be ideal if we could use the move keyword, but that causes the closure to also move in k, so we wouldn't be able to return it from the function.
Trying to solve that led to this version:
fn filter<F>(&mut self, f: F) -> Keeper
where F: Fn() -> bool + 'static //'
{
let mut k = Keeper::new();
let k2 = &mut k;
self.subscribe(move || {
if f() { k2.publish() }
});
k
}
which has a useful error message:
error: `k` does not live long enough
let k2 = &mut k;
^
note: reference must be valid for the static lifetime...
...but borrowed value is only valid for the block
Which leads to another problem: you are trying to keep a reference to k in the closure, but that reference will become invalid as soon as k is returned from the function. When items are moved by-value, their address will change, so references are no longer valid.
One potential solution is to use Rc and RefCell:
fn filter<F>(&mut self, f: F) -> Rc<RefCell<Keeper>>
where F: Fn() -> bool + 'static //'
{
let mut k = Rc::new(RefCell::new(Keeper::new()));
let k2 = k.clone();
self.subscribe(move || {
if f() { k2.borrow_mut().publish() }
});
k
}

Resources