I am trying to implement tree fold in rust. My first attempt compiles and runs as expected.
pub enum Tree<T> {
Leaf,
Node(Box<Tree<T>>, T, Box<Tree<T>>)
}
impl<T, U: Copy> Tree<T> {
fn fold(self, f: |l: U, x: T, r: U| -> U, acc: U) -> U {
match self {
Leaf => acc,
Node(box l, x, box r) => {
let l = l.fold(|l,x,r| {f(l,x,r)}, acc);
let r = r.fold(|l,x,r| {f(l,x,r)}, acc);
f(l, x, r)
}
}
}
}
fn main() {
let tl = Node(box Leaf, 1i, box Leaf);
let tr = Node(box Leaf, 2i, box Leaf);
let t = Node(box tl, 3i, box tr);
println!("size(t) == {}", t.fold(|l,_,r|{l + 1i + r}, 0))
}
However, when I try to move the implementation of size into the impl block to make it a method:
pub enum Tree<T> {
Leaf,
Node(Box<Tree<T>>, T, Box<Tree<T>>)
}
impl<T, U: Copy> Tree<T> {
fn fold(self, f: |l: U, x: T, r: U| -> U, acc: U) -> U {
match self {
Leaf => acc,
Node(box l, x, box r) => {
let l = l.fold(|l,x,r| {f(l,x,r)}, acc);
let r = r.fold(|l,x,r| {f(l,x,r)}, acc);
f(l, x, r)
}
}
}
fn size(self) -> uint {
self.fold(|l, _, r| {l + 1u + r}, 0u)
}
}
fn main() {
let tl = Node(box Leaf, 1i, box Leaf);
let tr = Node(box Leaf, 2i, box Leaf);
let t = Node(box tl, 3i, box tr);
println!("size(t) == {}", t.size())
}
I get the following error in the rust playpen.
<anon>:28:31: 28:39 error: cannot determine a type for this expression: unconstrained type
<anon>:28 println!("size(t) == {}", t.size())
^~~~~~~~
note: in expansion of format_args!
<std macros>:2:23: 2:77 note: expansion site
<std macros>:1:1: 3:2 note: in expansion of println!
<anon>:28:5: 29:2 note: expansion site
error: aborting due to previous error
playpen: application terminated with error code 101
Program ended.
I was hoping someone could shed some light on what I'm doing wrong and how to fix it.
There is a crucial difference between your two things.
In the first, you had this:
t.fold(|l,x,r|{l + x + r}, 0)
In the second, you have this (shown with self changed to t):
t.fold(|l, x, r| {l + 1 + r}, 0)
See the difference? l + 1 + r is not l + x + r.
(Since then, all cases have become l + 1 + r, for size, rather than l + x + r, for sum.)
After you’ve done that, you’ll run into issues because uint is not int. You’ll need to sort out your Ts and Us. Basically, you want l, x, r and 0 all to be of the same type, the T of earlier. This requires further constraints on T:
It must be Copy, to satisfy U.
You must be able to add a T to a T and get a T. This is std::num::Add<T, T>.
You must be able to get a zero of type T. That is the std::num::Zero trait and the Zero::zero() method.
You must be able to get a one of type T. That is the std::num::One trait and the One::one() method.
While we’re at it, U should probably be a generic on the fold function specifically rather than the impl block, though either will do.
In the end, we end up with this functioning code:
use std::num::Zero;
pub enum Tree<T> {
Leaf,
Node(Box<Tree<T>>, T, Box<Tree<T>>)
}
impl<T> Tree<T> {
fn fold<U: Copy>(self, f: |l: U, x: T, r: U| -> U, acc: U) -> U {
match self {
Leaf => acc,
Node(box l, x, box r) => {
let l = l.fold(|l, x, r| f(l, x, r), acc);
let r = r.fold(|l, x, r| f(l, x, r), acc);
f(l, x, r)
}
}
}
}
impl<T: Copy + Add<T, T> + Zero + One> Tree<T> {
fn size(self) -> T {
self.fold(|l: T, _: T, r: T| l + One::one() + r, Zero::zero())
}
}
fn main() {
let tl = Node(box Leaf, 1i, box Leaf);
let tr = Node(box Leaf, 2i, box Leaf);
let t = Node(box tl, 3i, box tr);
println!("size(t) == {}", t.size())
}
(Note how the curly braces around the contents of a closure aren’t necessary, too.)
Related
My previous QA
What is the type for |x| move |y| x + y?
Thanks to the provided answer, the following code works.
#![feature(type_alias_impl_trait)]
type Adder = impl Fn(isize) -> isize;
type Plus = fn(isize) -> Adder;
let plus: Plus = |x| move |y| x + y;
println!("{}", plus(9)(1)); //10
Based on this, now I try to re-define map Functor.
#![feature(type_alias_impl_trait)]
type Mapper<A, B> = impl Fn(Vec<A>) -> Vec<B>;
type Map = <A, B>(fn(fn(A) -> B) -> Mapper<A, B>);
let map:Map = |f| move |A| A.map(f);
let f = |a| a * 2;
let A = vec![1, 2, 3];
let B = map(f)(A);
However, the first line got an error: could not find defining uses, the second line, for <A, B> syntax error.
Is it possible to fix this?
It looks like you want a generic function, so define one directly:
#![feature(type_alias_impl_trait)]
fn main() {
type Mapper<A, B> = impl Fn(Vec<A>) -> Vec<B>;
//type Map<A, B> = fn(fn(A) -> B) -> Mapper<A, B>;
//let map: Map::<A, B> = |f| move |a: Vec<A>| a.into_iter().map(f).collect();
fn map2<A, B>(f: fn(A) -> B) -> Mapper<A, B> {
move |a| a.into_iter().map(f).collect()
}
let f = |a| a * 2;
let a = vec![1, 2, 3];
//let b = map(f)(a);
let b = map2(f)(a);
// show result
println!("{:?}", b);
}
Check this.
I'm new to Rust lang and wonder what difference between two blocks in fn main(), can anyone explain in words of lifetime.
Are .as_str() calls change the lifetime of x and y?
Whose lifetime does -> &a' str refer to? a,b,c at lifetime() returning position or z to receive the result?
I consider the variables x and y have the same lifetime scopes in both blocks. And that of z covers the x's and y's.
If (x: &'a str, y: &'a str, z: &'a str) demands same lifetime scope of x,y,z, both blocks should fail.
fn main()
{
let mut z = "123abc";
{//// CAN ONLY SUCCEED WHEN REMOVE THE BRACES OF THIS BLOCK
let x = String::from("ajoisd");
let y = String::from("aso");
z = lifetime(x.as_str(), y.as_str(), z);
}
{//// GOES WELL WITH/WITHOUT BRACES
let x = "ajoisd";
let y = "aso";
z = lifetime(x, y, z);
}
println!("{}", z);
}
fn lifetime<'a>(a: &'a str, b: &'a str, c: &'a str) -> &'a str
{
if a.len() > b.len() {a}
else if a.len() < b.len() {b}
else {c}
}
Strings "ajoisd" and "aso" have the 'static lifetime. They outlive any variable in the program. Variables x and y in the first block live only in this block which is less than the lifetime of z.
This question is more complex than Closure as function parameter “cannot infer an appropriate lifetime due to conflicting requirements”.
There's a recursive closure which move environmental variable into it.
The code below works, tool is a grab-bag of useful functions for functional programming includes making recursive closure:
extern crate tool;
use tool::prelude::*;
use std::cell::Cell;
fn main() {
let a = Cell::new(false);
let fib = fix(move |f, x| {
a.set(true);
if x == 0 || x == 1 {
x
} else {
// `f` is `fib`
f(x - 1) + f(x - 2)
}
});
println!("{}", fib(10));
}
I want to know is it possible to pass that closure to a function, then call that function in that closure, the code below throws an error.
extern crate tool;
use tool::prelude::*;
use std::cell::RefCell;
fn main() {
let a = RefCell::new(false);
let fib = fix(move |f, x| {
*a.borrow_mut() = true;
if x == 0 || x == 1 {
x
} else {
// `f` is `fib`
b(Box::new(f), x - 1) + f(x - 2)
}
});
fn b (c: Box<Fn(u64) -> u64>, n: u64) -> u64 {
c(n)
}
println!("{}", b(Box::new(fib), 10));
}
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:14:24
|
14 | b(Box::new(f), x - 1) + f(x - 2)
| ^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 8:19...
--> src/main.rs:8:19
|
8 | let fib = fix(move |f, x| {
| ___________________^
9 | | *a.borrow_mut() = true;
10 | | if x == 0 || x == 1 {
11 | | x
... |
15 | | }
16 | | });
| |_____^
= note: ...so that the expression is assignable:
expected &dyn std::ops::Fn(u64) -> u64
found &dyn std::ops::Fn(u64) -> u64
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::boxed::Box<(dyn std::ops::Fn(u64) -> u64 + 'static)>
found std::boxed::Box<dyn std::ops::Fn(u64) -> u64>
It looks like you are mixing several concepts here. First of all you must understand the difference between these:
fn(A) -> B
impl Fn(A) -> B or T: Fn(A) -> B
&dyn Fn(A) -> B
Box<dyn Fn(A) -> B>
Number 1 is the type of a pointer to a function, just like in C.
Number 2 is a generic type that implements the function trait Fn, that is a type that is callable.
Number 3 is a dynamic reference to a callable object (the dyn keyword is optional).
Number 4 is a trait object, that is a boxed callable object with the real type erased.
Now look at the definition of tool::fix:
pub fn fix<A, B, F>(f: F) -> impl Fn(A) -> B
where
F: Fn(&Fn(A) -> B, A) -> B,
From that you see that fix uses number 2 for the f parameter, but number 3 for the A parameter of f. Also, it returns number 2.
The tricky part here is that f is a function that takes a function as argument. The f itself can be any of any kind that implements Fn, but the first argument of that function must be of &dyn Fn kind.
Your original error comes from trying to box a &dyn Fn(A) -> B, but you cannot do that generically, because such a value may contain references, and Box requires a 'static type.
But with all that in mind you can carefully write your function without using Box, so your problem just disappears, and the result is nicer (playground):
fn main() {
fn wrap (wrap_fn: impl Fn(&dyn Fn(u64) -> u64, u64) -> u64) -> impl Fn(u64) -> u64 {
let a = RefCell::new(false);
let fib = fix(move |f, x| {
*a.borrow_mut() = true;
if x == 0 || x == 1 {
x
} else {
// `f` is `fib`
wrap_fn(f, x - 1) + wrap_fn(f, x - 2)
}
});
fib
}
fn b (c: &dyn Fn(u64) -> u64, n: u64) -> u64 {
c(n)
}
println!("{}", (wrap(b))(10));
}
I'm trying to write a function that composes two functions. The initial design is pretty simple: a function that takes two functions and returns a composed function which I can then compose with other functions, since Rust doesn't have rest parameters. I've run into a wall built with frustrating non-helpful compiler errors.
My compose function:
fn compose<'a, A, B, C, G, F>(f: F, g: G) -> Box<Fn(A) -> C + 'a>
where
F: 'a + Fn(A) -> B + Sized,
G: 'a + Fn(B) -> C + Sized,
{
Box::new(move |x| g(f(x)))
}
How I would like to use it:
fn main() {
let addAndMultiply = compose(|x| x * 2, |x| x + 2);
let divideAndSubtract = compose(|x| x / 2, |x| x - 2);
let finally = compose(*addAndMultiply, *divideAndSubtract);
println!("Result is {}", finally(10));
}
The compiler doesn't like that, no matter what I try, the trait bounds are never satisfied. The error is:
error[E0277]: the size for values of type `dyn std::ops::Fn(_) -> _` cannot be known at compilation time
--> src/main.rs:13:19
|
13 | let finally = compose(*addAndMultiply, *divideAndSubtract);
| ^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `dyn std::ops::Fn(_) -> _`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
note: required by `compose`
--> src/main.rs:1:1
|
1 | / fn compose<'a, A, B, C, G, F>(f: F, g: G) -> Box<Fn(A) -> C + 'a>
2 | | where
3 | | F: 'a + Fn(A) -> B + Sized,
4 | | G: 'a + Fn(B) -> C + Sized,
5 | | {
6 | | Box::new(move |x| g(f(x)))
7 | | }
| |_^
As #ljedrz points out, to make it work you only need to reference the composed functions again:
let finally = compose(&*multiply_and_add, &*divide_and_subtract);
(Note that in Rust, convention dictates that variable names should be in snake_case)
However, we can make this better!
Since Rust 1.26, we can use abstract return types (previously featured gated as #![feature(conservative_impl_trait)]). This can help you simplify your example greatly, as it allows you to skip the lifetimes, references, Sized constraints and Boxes:
fn compose<A, B, C, G, F>(f: F, g: G) -> impl Fn(A) -> C
where
F: Fn(A) -> B,
G: Fn(B) -> C,
{
move |x| g(f(x))
}
fn main() {
let multiply_and_add = compose(|x| x * 2, |x| x + 2);
let divide_and_subtract = compose(|x| x / 2, |x| x - 2);
let finally = compose(multiply_and_add, divide_and_subtract);
println!("Result is {}", finally(10));
}
Finally, since you mention rest parameters, I suspect that what you actually want is to have a way to chain-compose as many functions as you want in a flexible manner. I wrote this macro for this purpose:
macro_rules! compose {
( $last:expr ) => { $last };
( $head:expr, $($tail:expr), +) => {
compose_two($head, compose!($($tail),+))
};
}
fn compose_two<A, B, C, G, F>(f: F, g: G) -> impl Fn(A) -> C
where
F: Fn(A) -> B,
G: Fn(B) -> C,
{
move |x| g(f(x))
}
fn main() {
let add = |x| x + 2;
let multiply = |x| x * 2;
let divide = |x| x / 2;
let intermediate = compose!(add, multiply, divide);
let subtract = |x| x - 2;
let finally = compose!(intermediate, subtract);
println!("Result is {}", finally(10));
}
Just add references in finally and it will work:
fn main() {
let addAndMultiply = compose(|x| x * 2, |x| x + 2);
let divideAndSubtract = compose(|x| x / 2, |x| x - 2);
let finally = compose(&*addAndMultiply, &*divideAndSubtract);
println!("Result is {}", finally(10));
}
Dereferencing addAndMultiply or divideAndSubtract uncovers a trait object which is not Sized; it needs to either be wrapped in a Box or referenced in order for it to be passed to a function with a Sized constraint.
macro_rules! comp {
($f: expr) => {
move |g: fn(_) -> _| move |x: _| $f(g(x))
};
}
fn main() {
let add1 = |x| x + 1;
let add2 = |x| x + 2;
let add3 = comp!(add1)(add2);
println!("{}", add3(3));
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=1c6915d94f7e1e35cf93fb21daceb9ef
fn add(x: i32, y: i32) -> fn() {
let z = x + y;
mul(z, 2);
}
fn mul(x1: i32, y1: i32) -> fn() {
let z1 = x1 * y1;
sub(z1, 2);
}
fn sub(x2: i32, y2: i32) -> (i32) {
let z2 = x2 - y2;
z2
}
fn main() {
let R = add(2, 2);
println!("{}", R);
}
Assigning R to add(2, 2) doesn't work. I need to be able to assign R from add -> mul -> sub which returns z2.
So, the process is add(2, 2) -> mul(4, 2) -> sub(8, 2) thus getting R = 6. How do I go about doing this?
This is the error I get:
error[E0277]: the trait bound `fn(i32): std::fmt::Display` is not satisfied
--> testzz.rs:20:16
|
20 | println!("{}", R);
| ^ the trait `std::fmt::Display` is not implemented for
`fn(i32)`
|
= note: `fn(i32)` cannot be formatted with the default formatter; try using
`:?` instead if you are using a format string
= note: required by `std::fmt::Display::fmt`
It seems to me that you are confused about the syntax of return types of functions. The code compiles perfectly after a couple of minor edits:
fn add(x: i32, y: i32) -> i32 {
let z = x + y;
mul(z, 2)
}
fn mul(x1: i32, y1: i32) -> i32 {
let z1 = x1 * y1;
sub(z1, 2)
}
fn sub(x2: i32, y2: i32) -> i32 {
let z2 = x2 - y2;
z2
}
Note that the return type of all functions is now i32. Returning fn() means something completely different and doesn't make sense in this case. Also, I removed the semicolons at the end of add and mul so Rust knows that they are the return values.