Issue with lifetime parameters and function pointers - rust

Consider this code:
struct WithLifetime<'a> {
s: &'a str
}
impl WithLifetime<'_> {
fn in_impl(&self) -> bool {
self.s == "a"
}
}
fn out_of_impl(wl: &WithLifetime<'_>) -> bool {
wl.s == "a"
}
fn higher_order(f: fn(&WithLifetime<'_>) -> bool) -> bool {
let s = "a";
let wl = WithLifetime { s };
f(&wl)
}
fn main() {
higher_order(out_of_impl); // This line compiles
higher_order(WithLifetime::in_impl); // This line does not
}
The final line of main fails to compile with this error:
error[E0308]: mismatched types
--> src/main.rs:23:18
|
23 | higher_order(WithLifetime::in_impl); // This line does not
| ^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'r, 's> fn(&'r WithLifetime<'s>) -> _`
found fn pointer `for<'r> fn(&'r WithLifetime<'_>) -> _`
As far as I can figure out, in_impl and out_of_impl should be exactly the same function. They both take a reference to a WithLifetime, and don't care about the lifetime of that reference or the lifetime parameter of the WithLifetime instance. Both should be valid parameters to pass to higher_order. The compiler does not agree.
What is the problem with passing in_impl to higher_order, and why doesn't the compiler allow this? What can I do to pass struct methods on structs with lifetime parameters to higher-order functions?

First, let's find out the types for all the 3 functions:
fn main() {
let x: i32 = out_of_impl;
let x: i32 = WithLifetime::in_impl;
let x: i32 = higher_order;
}
Playground
Type of out_of_impl:
for<'r, 's> fn(&'r WithLifetime<'s>) -> bool {out_of_impl}
Type of WithLifetime::in_impl:
for<'r> fn(&'r WithLifetime<'_>) -> bool {WithLifetime::<'_>::in_impl}
Type of higher_order:
fn(for<'r, 's> fn(&'r WithLifetime<'s>) -> bool) -> bool {higher_order}
higher_order accepts a function in which both the lifetimes aren't named until the function is called.
So it basically accepts a function which works for any lifetimes 'r and 's. out_of_impl satisfies that criteria.
But in case of WithLifetime::in_impl, the inner lifetime needs to be known beforehand for<'r> fn(&'r WithLifetime<'_>).
To pass WithLifetime::in_impl, you would need to change it to:
fn in_impl<'b, 'c>(abc: &'b WithLifetime<'c>) -> bool {
abc.s == "a"
}
Playground
Now, this function works for any arbitrary lifetimes 'b and 'c.
To accept in_impl without changing it, as #Milan did,
fn higher_order<'b>(f: fn(&WithLifetime<'b>) -> bool) -> bool {
let s = "a";
let wl = WithLifetime { s };
f(&wl)
}
Playground
Now, higher_order has a type:
for<'b> fn(for<'r> fn(&'r WithLifetime<'b>) -> bool) -> bool {higher_order}
It accepts a function where lifetime 'r is defined only when the function is called and liftime 'b is known beforehand.
This works for out_of_impl because it accepts any arbitrary lifetimes. Also works for in_impl because now the signature matches higher_order.
How does for<> syntax differ from a regular lifetime bound? has a pretty nice explaination for HRTB.

In higher_order function, wl is dropped before it is borrowed, instead, change that function to this
fn higher_order<'b>(f: fn(&WithLifetime<'b>) -> bool) -> bool {
let s = "a";
let wl= WithLifetime { s };
f(&wl)
}
EDIT:
In simple words, fn higher_order<'b>(f: fn(&WithLifetime<'b>) -> bool) -> bool this 'b means that higher_order body lifetime will match fn lifetime.
Otherwise, if fn don't care what lifetime higher_order has, and this implicitly means wl value too since it is the body of high_order function, then compiler can drop wl at the same line it is declared since point is to save memory, right?

Related

Can Rust cast between function types when I don't care about some of the arguments?

I have 3 function types:
type ThreadedFunction = fn(&mut Thread, Object) -> FunctionResult;
type UniversalFunction = fn(&mut Thread, Unused) -> FunctionResult;
type Function = fn(&mut Thread, &Method) -> FunctionResult;
static_assertions::assert_eq_size!(primitives::Unused, &Method);
static_assertions::assert_eq_size!(primitives::Unused, Object);
The universal functions ignore the second parameter, so I'd like to be able to use them in the two other contexts. The sizes of Object, Unused and &Method are the same.
I would like to be able to do something like:
pub fn unused(thread: &mut Thread, _: Unused) -> FunctionResult {
NormalReturn
}
pub fn somewhere() -> ThreadedFunction {
unused as ThreadedFunction
}
This is unsafe:
error[E0605]: non-primitive cast: `for<'r> fn(&'r mut interpreter::Thread, interpreter::primitives::Unused) -> interpreter::FunctionResult {unused}` as `for<'r> fn(&'r mut interpreter::Thread, object::Object) -> interpreter::FunctionResult`
--> src/interpreter.rs:25:13
|
25 | unused as ThreadedFunction
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
Wrapping the cast in unsafe {} doesn't help.
This could be impossible, but it would be very convenient to be able to do as it would save a bunch of code duplication.
No, you cannot perform this cast because the function references have different types. All of the parameter types and return types must be the same for two functions to have the same type.
Instead, you can return a closure that doesn't capture any environment. Because of that, it can be automatically converted into a function:
fn somewhere() -> ThreadedFunction {
|a, b| unused(a, Unused)
}
That is equivalent to this wrapper function:
fn unused_adapted(thread: &mut Thread, _: Object) -> FunctionResult {
unused(thread, Unused)
}
fn somewhere() -> ThreadedFunction {
unused_adapted
}
See also:
Why does passing a closure to function which accepts a function pointer not work?

Type of a function pointer to method with lifetime parameters

I have a struct with a lifetime and some methods:
struct Ctrl<'a> {
x: &'a i32,
}
impl<'a> Ctrl<'a> {
fn foo(&self) -> i32 {
*self.x + 1
}
fn bar(&self) -> i32 {
*self.x + 2
}
}
Now I want to store pointers to the methods in a slice, kind of like a look-up table:
const LIST: &[_] = &[Ctrl::foo, Ctrl::bar];
Rust demands to know the slice element type and suggests for<'r> fn(&'r Ctrl) -> i32, but this results in an error:
error[E0308]: mismatched types
--> main.rs:16:48
|
16 | const LIST: &[for<'r> fn(&'r Ctrl) -> i32] = &[Ctrl::foo, Ctrl::bar];
| ^^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'s, 'r> fn(&'r Ctrl<'s>) -> _`
found fn pointer `for<'r> fn(&'r Ctrl<'_>) -> _`
Is there a way to specify the correct type?
The problem is that foo is a method of Ctrl<'x> for some specific lifetime 'x, and not a method generic over all Ctrl<'_>. If you try to make all the lifetimes explicit, you will find that some of them can't be expressed:
const LIST: &[for<'a, 'b> fn(&'b Ctrl<'a>) -> i32] = &[Ctrl::<'?>::foo, Ctrl::<'?>::bar)];
// What lifetimes? ^^^^ ^^^^
Since foo isn't generic, but is bound to a specific Ctrl<'_>, there's no way to express the concept you need. You might try something like <for<'a> Ctrl<'a>>::foo, but that's not legal in current Rust.
One way to fix this would be to wrap each method in a closure that can be coerced to a function pointer:
const LIST: &[fn(&Ctrl<'_>) -> i32] = &[|this| this.foo(), |this| this.bar()];
This might get a little verbose if you have a lot of methods or if the signatures are more complex. Another option is to wrap each method in a free function with the correct signature. You could write a declarative macro to make it easier:
/// Wrap `Ctrl::$method` in a free function and return it.
macro_rules! ctrl {
($method:ident) => {{
fn inner(this: &Ctrl<'_>) -> i32 {
this.$method()
}
inner
}};
}
const LIST: &[fn(&Ctrl<'_>) -> i32] = &[ctrl!(foo), ctrl!(bar)];

How to convert a generic function into a function pointer with a reference parameter?

pub fn remove_file<P: AsRef<Path>>(path: P) -> Result<()>;
I am struggling to cast std::fs::remove_file to a function pointer:
Playground
use std::{io, fs, path::Path};
fn main() {
let _: fn(&Path) -> io::Result<()> = &fs::remove_file;
// let _: &dyn FnOnce(&Path) -> io::Result<()> = &fs::remove_file;
}
The error is the following:
error[E0308]: mismatched types
--> src/main.rs:4:43
|
4 | let _: fn(&Path) -> io::Result<()> = &fs::remove_file;
| --------------------------- ^^^^^^^^^^^^^^^^ expected fn pointer, found reference
| |
| expected due to this
|
= note: expected fn pointer `for<'r> fn(&'r std::path::Path) -> std::result::Result<(), std::io::Error>`
found reference `&fn(_) -> std::result::Result<(), std::io::Error> {std::fs::remove_file::<_>}`
The problem might be with the for<'r> higher-order lifetimes requirement, but I don't know how to solve it.
How would I do it with a trait object? The following doesn't compile either:
let _: &dyn FnOnce(&Path) -> io::Result<()> = &fs::remove_file;
I know I can make a wrapper function around fs::remove_file, but I'd like to avoid that and get fs::remove_file to become a function pointer or trait object itself.
This is not a duplicate of this Function pointers in Rust using constrained generics as I'd like to get a function pointer to the concrete instantiation of std::fs::remove_file with &Path as a type parameter, but not to have a generic function pointer type.
I tried the following and it doesn't work either:
use std::{io, fs, path::Path};
fn main() {
let _: fn(&Path) -> io::Result<()> = &fs::remove_file::<&Path>;
}
I'd like to get a function pointer to the concrete instantiation of std::fs::remove_file with &Path as a type parameter, but not to have a generic function pointer type.
This is the heart of the issue. A concrete instantiation will compile. For example:
let _ : fn(&'static Path) -> io::Result<()> = fs::remove_file::<&'static Path>;
let _ : fn(&'r Path) -> io::Result<()> = fs::remove_file::<&'r Path>;
let _ : fn(&'long Path) -> io::Result<()> = fs::remove_file::<&'short Path>;
What you are trying to do is coerce from fs::remove_file of type:
∀ P: AsRef<Path>, P → io::Result<()>
to the type:
∀ 'r, &'r Path → io::Result<()>
The function pointer type is still generic over the lifetime. I don't think there's a reason this coercion couldn't be done, but Rust has some issues in this area.
The most straightforward workaround that Rust understands is to use a closure:
let _ : fn(&Path) -> io::Result<()> = |p| fs::remove_file(p);

How to implement the Y combinator in Rust? [duplicate]

I've just started Rust tutorial and ended with such code using recursion
extern crate rand;
use std::io;
use rand::Rng;
use std::cmp::Ordering;
use std::str::FromStr;
use std::fmt::{Display, Debug};
fn try_guess<T: Ord>(guess: T, actual: T) -> bool {
match guess.cmp(&actual) {
Ordering::Less => {
println!("Too small");
false
}
Ordering::Greater => {
println!("Too big");
false
}
Ordering::Equal => {
println!("You win!");
true
}
}
}
fn guess_loop<T: Ord + FromStr + Display + Copy>(actual: T)
where <T as FromStr>::Err: Debug
{
println!("PLease input your guess.");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
let guess_int: T = guess.trim()
.parse()
.expect("Should enter integer number");
println!("You guessed {} !", guess_int);
if !try_guess(guess_int, actual) {
guess_loop(actual)
}
}
fn main() {
println!("Guess the number!!!");
let secret_number = rand::thread_rng().gen_range(1, 51);
guess_loop(secret_number);
}
I was hoping to factor-out the recursion from the guess_loop function and introduced a fix point operator:
fn guess_loop<T: Ord + FromStr + Display + Copy>(actual: T, recur: fn(T) -> ()) -> ()
where <T as FromStr>::Err: Debug
{
println!("PLease input your guess.");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
let guess_int: T = guess.trim()
.parse()
.expect("Should enter integer number");
println!("You guessed {} !", guess_int);
if !try_guess(guess_int, actual) {
recur(actual)
}
}
fn fix<T, R>(func: fn(T, fn(T) -> R) -> R) -> fn(T) -> R {
fn fixed(val: T) -> R {
func(val, fixed)
}
fixed
}
fn main() {
println!("Guess the number!!!");
let secret_number = rand::thread_rng().gen_range(1, 51);
fix(guess_loop)(secret_number);
}
but this led to numerous errors, such as
error[E0401]: can't use type parameters from outer function; try using a local type parameter instead
--> src/main.rs:49:19
|
49 | fn fixed(val: T) -> R {
| ^ use of type variable from outer function
error[E0401]: can't use type parameters from outer function; try using a local type parameter instead
--> src/main.rs:49:25
|
49 | fn fixed(val: T) -> R {
| ^ use of type variable from outer function
error[E0434]: can't capture dynamic environment in a fn item; use the || { ... } closure form instead
--> src/main.rs:50:9
|
50 | func(val, fixed)
| ^^^^
My next attempt was changing guess_loop's definition to
fn guess_loop<T: Ord + FromStr + Display + Copy, F>(actual: T, recur: F) -> ()
where <T as FromStr>::Err: Debug,
F: Fn(T) -> ()
{ ... }
and redefine fix as
fn fix<T, R, F>(func: fn(T, F) -> R) -> F
where F: Fn(T) -> R
{
let fixed = |val: T| func(val, fix(func));
fixed
}
this led to
error[E0308]: mismatched types
--> src/main.rs:53:5
|
53 | fixed
| ^^^^^ expected type parameter, found closure
|
= note: expected type `F`
= note: found type `[closure#src/main.rs:52:17: 52:46 func:_]`
error: the type of this value must be known in this context
--> src/main.rs:61:5
|
61 | fix(guess_loop)(secret_number);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
How can I write a similar fix function?
Firstly, variable names don't exist until after they're initialised. You can't have fixed refer to itself like that.
Secondly, you can't return closures by-value from a function, period. Generic parameters are chosen by the caller, and the caller has no idea what the type of a closure inside the function is going to be.
I'm not claiming that what follows is the best way of doing this, but it was the simplest I was able to come up with that type-checks.
fn guess_loop<T>(actual: T, recur: &Fn(T)) -> ()
where T: Ord + FromStr + Display + Copy,
<T as FromStr>::Err: Debug
{
// ...
}
fn fix<T, R, F>(func: F) -> Box<Fn(T) -> R>
where T: 'static,
R: 'static,
F: Fn(T, &Fn(T) -> R) -> R + 'static
{
use std::cell::RefCell;
use std::rc::Rc;
let fixed = Rc::new(RefCell::new(None));
let fixed_fn = {
let fixed = fixed.clone();
move |val: T| -> R {
let fixed_ref = fixed.borrow();
let fixed_ref: &Box<_> = fixed_ref.as_ref().unwrap();
func(val, &**fixed_ref)
}
};
*fixed.borrow_mut() = Some(Box::new(fixed_fn));
Box::new(move |val: T| -> R {
let fixed_ref = fixed.borrow();
let fixed_ref: &Box<_> = fixed_ref.as_ref().unwrap();
fixed_ref(val)
})
}
In order for fixed_fn to refer to itself, we have to create something for it to read from before it exists. Unfortunately, this means having a cycle, and Rust hates cycles. So, we do this by constructing a reference-counted RefCell<Option<_>> that starts with None, and which will be mutated later to contain the fixed-point closure.
Secondly, we can't use this handle as a callable, so we have to explicitly pull a pointer to the closure out so that we can pass it to func.
Third, the compiler doesn't seem to be able to infer the type of fixed correctly. I was hoping it would be able to work out that it is Rc<RefCell<Option<{closure}>>>, but it refused to do so. As a result, we have to resort to storing a Box<Fn(T) -> R>, since we can't name the type of the closure explicitly.
Finally, we have to construct a new closure that takes a second handle to fixed, unpacks it, and calls it. Again, we can't use fixed as a callable directly. We also can't re-use the closure inside fixed, because to do that we'd have to put that inside its own Rc and at that point, things are starting to get crazy.
... more crazy.
Finally, we have to return this second closure in a Box because, as I said before, we can't return closures by value because we can't name their types in the signature.
*deep breath*
If someone has a simpler solution, I'd love to see it. :P
This is an answer to my own question about implementing the Y combinator which is a subset of this question. In pure lambda expression, a version of the Y combinator looks like
λf.(λw.w w)(λw.f (w w))
The solution in Rosetta Code is too complicated and used Box to allocate memory in the heap. I want to simplify this.
First, let's implement the type Mu<T> as a trait instead.
trait Mu<T> {
fn unroll(&self, &Mu<T>) -> T;
}
Note that we need this trait to be object safe, which means we cannot ask for Self in any of its definition so the second parameter is typed &Mu<T> and it is a trait object.
Now we can write a generic trait implementation:
impl<T, F: Fn(&Mu<T>) -> T> Mu<T> for F {
fn unroll(&self, o: &Mu<T>) -> T {
self(o)
}
}
With this, we can now write the y combinator as the following:
fn y<T, F: Fn(T) -> T>(f: &F) -> T {
(&|w: &Mu<T>| w.unroll(w))(&|w: &Mu<T>| f(w.unroll(w)))
}
The above compiles in the Rust playground without enabling any features and using only the stable channel so this is a pretty good answer to my question.
However, the above would not work in practice because Rust is call-by-value but the code above is the call-by-name Y combinator.
The call-by-value solution
To work with the stable channel without requiring any features, we cannot return closures (which requires impl Trait). Instead, I came up with making another Mu2 type that takes two type parameters:
trait Mu2<T, R> {
fn unroll(&self, &Mu2<T, R>, t: T) -> R;
}
As above, let's implement this new trait.
impl<T, R, F> Mu2<T, R> for F
where
F: Fn(&Mu2<T, R>, T) -> R,
{
fn unroll(&self, o: &Mu2<T, R>, t: T) -> R {
self(o, t)
}
}
The new Y combinator:
fn y<T, R, F>(f: &F, t: T) -> R
where
F: Fn(&Fn(T) -> R, T) -> R,
{
(&|w: &Mu2<T, R>, t| w.unroll(w, t))((&|w: &Mu2<T, R>, t| f(&|t| w.unroll(w, t), t)), t)
}
Now it is time to test our new facility.
fn main() {
let fac = &|f: &Fn(i32) -> i32, i| if i > 0 { i * f(i - 1) } else { 1 };
println!("{}", y(fac, 10))
}
Results in:
3628800
All done!
You can see that the y function has a slightly different signature than the questioner's fix, but it shouldn't matter.
The direct recurring version
The same technology to avoid returning a closure can be used for the normal direct recurring version as well:
fn fix<T, R, F>(f: &F, t: T) -> R
where
F: Fn(&Fn(T) -> R, T) -> R,
{
f(&|t| fix(f, t), t)
}
fn fib(i: i32) -> i32 {
let fn_ = &|f:&Fn(i32) -> i32, x| if x < 2 { x } else { f(x-1) + f(x-2) };
fix(fn_, i)
}
Basically, whenever you need to return a closure from a function, you can add the closure's parameter to the function, and change the return type to the closure's return type. Later on when you need a real closure, just create the closure by partial evaluating that function.
Further discussions
Compare to other languages, in Rust there is a big difference: the function given to find fix point must not have any internal states. In Rust this is a requirement that the F type parameter of y must be Fn, not FnMut or FnOnce.
For example, we cannot implement a fix_mut that would be used like
fn fib1(i: u32) -> u32 {
let mut i0 = 1;
let mut i1 = 1;
let fn_ = &mut |f:&Fn(u32) -> u32, x|
match x {
0 => i0,
1 => i1,
_ => {
let i2 = i0;
i0 = i1;
i1 = i1 + i2;
f(x)
}
};
fix_mut(fn_, i)
}
without unsafe code whilst this version, if it works, performs much better (O(N)) than the version given above (O(2^N)).
This is because you can only have one &mut of one object at a single time. But the idea of Y combinator, or even the fix point function, requires capturing/passing the function at the same time when calling it, that's two references and you can't just mark any of them immutable without marking another so.
On the other hand, I was wonder if we could do something that other languages usually not able to but Rust seems to be able. I was thinking restricting the first argument type of F from Fn to FnOnce (as y function will provide the implementation, change to FnMut does not make sense, we know it will not have states, but change to FnOnce means we want it to be used only once), Rust would not allow at the moment as we cannot pass unsized object by value.
So basically, this implementation is the most flexible solution we could think of.
By the way, the work around of the immutable restriction is to use pseudo-mutation:
fn fib(i: u32) -> u32 {
let fn_ = &|f:&Fn((u32,u32,u32)) -> u32, (x,i,j)|
match x {
0 => i,
1 => j,
_ => {
f((x-1,j,i+j))
}
};
fix(&fn_, (i,1,1))
}
Starting at where you left off:
fn fix<T, R, F>(func: fn(T, F) -> R) -> F
where F: Fn(T) -> R
{
|val: T| func(val, fix(func))
}
The returned object has an unnameable closure type. Using a generic type won’t help here, since the type of the closure is decided by the callee, not the caller. Here’s where impl traits come in handy:
fn fix<T, R, F>(func: fn(T, F) -> R) -> impl Fn(T) -> R
where F: Fn(T) -> R
{
|val: T| func(val, fix(func))
}
We can’t pass fix(func) to func because it expects a nameable type for F. We’ll have to settle for a trait object instead:
fn fix<T, R>(func: fn(T, &Fn(T) -> R) -> R) -> impl Fn(T) -> R {
|val: T| func(val, &fix(func))
}
Now it’s time to fight the lifetime checker. The compiler complains:
only named lifetimes are allowed in `impl Trait`, but `` was found in the type `…`
This is a somewhat cryptic message. Since impl traits are always 'static by default, this is a roundabout way of saying: “the closure does not live long enough for 'static”. To get the real error message, we append + 'static to the impl Fn(T) -> R and recompile:
closure may outlive the current function, but it borrows `func`, which is owned by the current function
So that was the real problem. It is borrowing func. We don’t need to borrow func because fn is Copy, so we can duplicate it as much as we want. Let’s prepend the closure with move and get rid of the + 'static from earlier:
fn fix<T, R>(func: fn(T, &Fn(T) -> R) -> R) -> impl Fn(T) -> R {
move |val: T| func(val, &fix(func))
}
And voila, it works! Well, almost … you’ll have to edit guess_loop and change fn(T) -> () to &Fn(T) -> (). I’m actually quite amazed that this solution doesn’t require any allocations.
If you can’t use impl traits, you can instead write:
fn fix<T, R>(func: fn(T, &Fn(T) -> R) -> R) -> Box<Fn(T) -> R>
where T: 'static,
R: 'static
{
Box::new(move |val: T| func(val, fix(func).as_ref()))
}
which is unfortunately not allocation-free.
Also, we can generalize the result a bit to allow arbitrary closures and lifetimes:
fn fix<'a, T, R, F>(func: F) -> impl 'a + Fn(T) -> R
where F: 'a + Fn(T, &Fn(T) -> R) -> R + Copy
{
move |val: T| func(val, &fix(func))
}
In the process of figuring out a solution for your problem, I ended up writing a simpler version of fix, which actually ended up guide me towards a solution to your fix function:
type Lazy<'a, T> = Box<FnBox() -> T + 'a>;
// fix: (Lazy<T> -> T) -> T
fn fix<'a, T, F>(f: F) -> T
where F: Fn(Lazy<'a, T>) -> T + Copy + 'a
{
f(Box::new(move || fix(f)))
}
Here’s a demonstration of how this fix function could be used to calculate the factorial:
fn factorial(n: u64) -> u64 {
// f: Lazy<u64 -> u64> -> u64 -> u64
fn f(fac: Lazy<'static, Box<FnBox(u64) -> u64>>) -> Box<FnBox(u64) -> u64> {
Box::new(move |n| {
if n == 0 {
1
} else {
n * fac()(n - 1)
}
})
}
fix(f)(n)
}
This can be done at zero runtime cost if you're willing to use unstable features (i.e. a nightly compiler) and willing to... obfuscate your code slightly.
First, we need to turn the result of fix into a named struct. This struct needs to implement Fn, so we'll implement it manually (this is an unstable feature).
#![feature(fn_traits)]
#![feature(unboxed_closures)]
extern crate rand;
use rand::Rng;
use std::cmp::Ordering;
fn try_guess<T: Ord>(guess: T, actual: T) -> bool {
match guess.cmp(&actual) {
Ordering::Less => {
println!("Too small");
false
}
Ordering::Greater => {
println!("Too big");
false
}
Ordering::Equal => {
println!("You win!");
true
}
}
}
struct Fix<F>
where F: Fn(i32, &Fix<F>)
{
func: F,
}
impl<F> FnOnce<(i32,)> for Fix<F>
where F: Fn(i32, &Fix<F>)
{
type Output = ();
extern "rust-call" fn call_once(self, args: (i32,)) -> Self::Output {
self.call(args)
}
}
impl<F> FnMut<(i32,)> for Fix<F>
where F: Fn(i32, &Fix<F>)
{
extern "rust-call" fn call_mut(&mut self, args: (i32,)) -> Self::Output {
self.call(args)
}
}
impl<F> Fn<(i32,)> for Fix<F>
where F: Fn(i32, &Fix<F>)
{
extern "rust-call" fn call(&self, (val,): (i32,)) -> Self::Output {
(self.func)(val, self);
}
}
fn fix<F>(func: F) -> Fix<F>
where F: Fn(i32, &Fix<F>)
{
Fix { func: func }
}
fn guess_loop<F>(actual: i32, recur: &F)
where F: Fn(i32)
{
let guess_int = rand::thread_rng().gen_range(1, 51);
if guess_int != actual {
recur(actual)
}
}
fn main() {
let secret_number = rand::thread_rng().gen_range(1, 51);
fix(guess_loop)(secret_number);
}
However, we're not done yet. This fails to compile with the following error:
error[E0281]: type mismatch: the type `fn(i32, &_) {guess_loop::<_>}` implements the trait `for<'r> std::ops::Fn<(i32, &'r _)>`, but the trait `for<'r> std::ops::Fn<(i32, &'r Fix<fn(i32, &_) {guess_loop::<_>}>)>` is required (cyclic type of infinite size)
--> src/main.rs:77:5
|
77 | fix(guess_loop)(secret_number);
| ^^^
|
= note: required by `fix`
Note: In case you're not aware, in Rust, each function has its own, zero-sized type. If a function is generic, then each instantiation of that function will have its own type as well. For example, the type of guess_loop::<X> will be reported by the compiler as fn(i32, &X) {guess_loop::<X>} (as you can see in the error message above, except with underscores where the concrete type hasn't been resolved yet). That type can be coerced to a function pointer type implicitly in some contexts or explicitly with a cast (as).
The problem is that, in the expression fix(guess_loop), the compiler needs to instantiate guess_loop, which is a generic function, and it looks like the compiler isn't able to figure out the proper type to instantiate it with. In fact, the type we would like to set for type parameter F references the type of guess_loop. If we were to write it out in the style reported by the compiler, the type would look like fn(i32, &Fix<X>) {guess_loop::<Fix<&X>>}, where X is replaced by the type itself (you can see now where the "cyclic type of infinite size" comes from).
We can solve this by replacing the guess_loop function by a non-generic struct (we'll call it GuessLoop) that implements Fn by referring to itself. (You can't do this with a normal function because you can't name a function's type.)
struct GuessLoop;
impl<'a> FnOnce<(i32, &'a Fix<GuessLoop>)> for GuessLoop {
type Output = ();
extern "rust-call" fn call_once(self, args: (i32, &Fix<GuessLoop>)) -> Self::Output {
self.call(args)
}
}
impl<'a> FnMut<(i32, &'a Fix<GuessLoop>)> for GuessLoop {
extern "rust-call" fn call_mut(&mut self, args: (i32, &Fix<GuessLoop>)) -> Self::Output {
self.call(args)
}
}
impl<'a> Fn<(i32, &'a Fix<GuessLoop>)> for GuessLoop {
extern "rust-call" fn call(&self, (actual, recur): (i32, &Fix<GuessLoop>)) -> Self::Output {
let guess_int = rand::thread_rng().gen_range(1, 51);
if !try_guess(guess_int, actual) {
recur(actual)
}
}
}
fn main() {
let secret_number = rand::thread_rng().gen_range(1, 51);
fix(GuessLoop)(secret_number);
}
Notice that GuessLoop's implementation of Fn is no longer generic on the type of the recur parameter. What if we tried to make the implementation of Fn generic (while still leaving the struct itself non-generic, to avoid cyclic types)?
struct GuessLoop;
impl<'a, F> FnOnce<(i32, &'a F)> for GuessLoop
where F: Fn(i32),
{
type Output = ();
extern "rust-call" fn call_once(self, args: (i32, &'a F)) -> Self::Output {
self.call(args)
}
}
impl<'a, F> FnMut<(i32, &'a F)> for GuessLoop
where F: Fn(i32),
{
extern "rust-call" fn call_mut(&mut self, args: (i32, &'a F)) -> Self::Output {
self.call(args)
}
}
impl<'a, F> Fn<(i32, &'a F)> for GuessLoop
where F: Fn(i32),
{
extern "rust-call" fn call(&self, (actual, recur): (i32, &'a F)) -> Self::Output {
let guess_int = rand::thread_rng().gen_range(1, 51);
if !try_guess(guess_int, actual) {
recur(actual)
}
}
}
Unfortunately, this fails to compile with the following error:
error[E0275]: overflow evaluating the requirement `<Fix<GuessLoop> as std::ops::FnOnce<(i32,)>>::Output == ()`
--> src/main.rs:99:5
|
99 | fix(GuessLoop)(secret_number);
| ^^^
|
= note: required because of the requirements on the impl of `for<'r> std::ops::Fn<(i32, &'r Fix<GuessLoop>)>` for `GuessLoop`
= note: required by `fix`
Essentially, the compiler is unable to verify that Fix<GuessLoop> implements Fn(i32), because in order to do that, it needs to verify that GuessLoop implements Fn(i32, &Fix<GuessLoop>), but that is only true if Fix<GuessLoop> implements Fn(i32) (because that impl is conditional), which is only true if GuessLoop implements Fn(i32, &Fix<GuessLoop>) (because that impl is conditional too), which... you get the idea. In order words, the two implementations of Fn here are dependent on each other, and the compiler is unable to resolve that.

How do I capture a closure in another closure?

type Time = f32;
type Behaviour<'a,T> = |Time|: 'a -> T;
fn map_one<'a,T,R>(f: |T| -> R
,b: Behaviour<'a,T>)
-> Behaviour<'a,R>{
|time| -> R {
f(b(time))
}
}
Err:
<anon>:8:9: 8:10 error: captured variable `b` does not outlive the enclosing closure
<anon>:8 f(b(time))
^
<anon>:6:38: 10:2 note: captured variable is valid for the block at 6:37
<anon>:6 -> Behaviour<'a,R>{
<anon>:7 |time| -> R {
<anon>:8 f(b(time))
<anon>:9 }
<anon>:10 }
I think the error means that the life time of 'a expires when I try to move b into another closure.
How would I express something like this?
Your code is using "boxed" closures. Those closures capture values by reference, so the captured value must live longer than the closure. You're trying to capture b, which is a parameter, so its lifetime is the duration of the function call. You cannot do what you want to do with "boxed closures.
Unboxed closures were added to the language to solve issues like this. Here's how map_one would be defined:
#![feature(overloaded_calls, unboxed_closures, unboxed_closure_sugar)]
type Time = f32;
fn map_one<'a, T, R, F: Fn<(T,), R>, B: Fn<(Time,), T>>(
f: F, b: B) -> Box<Fn<(Time,), R>+'a> {
box |&: time| -> R {
f(b(time))
}
}
Fn is a trait with a call method that takes self by immutable reference (FnMut takes self by mutable reference and FnOnce takes self by value). The captured values are moved into the closure, rather than referenced.
The input closure parameters are defined with a type parameter that implements the Fn trait, which is the only way to pass closures by value. The return value, however, must be boxed, because the concrete result type (which implements Fn) is created by the compiler, and we can't name it.
I tried writing a main that uses map_one, but I'm getting an internal compiler error... At that point, I can't tell if I made a mistake or if the code is supposed to be valid. (These Rust issues may be related to this error: #16672, #16791, #17060.)
fn main() {
let t = 30f32;
let fa = |&: a: String| -> uint { a.len() };
let fb = |&: b: f32| -> String { b.to_string() };
let m = map_one(fa, fb);
let r = m.call((t,));
println!("{}", r);
}
Note: I couldn't use your Behaviour generic type alias to bound B.
#![feature(overloaded_calls, unboxed_closures, unboxed_closure_sugar)]
type Time = f32;
type Behaviour<T> = Fn<(Time,), T>;
fn map_one<'a, T, R, F: Fn<(T,), R>, B: Behaviour<T>>(
f: F, b: B) -> Box<Behaviour<R>+'a> {
box |&: time| -> R {
f(b(time))
}
}
The compiler complains:
<anon>:6:41: 6:53 error: `Behaviour` is not a trait
<anon>:6 fn map_one<'a, T, R, F: Fn<(T,), R>, B: Behaviour<T>>(
^~~~~~~~~~~~
<anon>:6:41: 6:53 note: `type` aliases cannot be used for traits
<anon>:6 fn map_one<'a, T, R, F: Fn<(T,), R>, B: Behaviour<T>>(
^~~~~~~~~~~~

Resources