If I have an list of numbers [1, 2, 3, 4, 5] and I wanted to generate a cumulative sum list, in Haskell I would do the following:
> let xs = [1, 2, 3, 4, 5]
> scanl (+) 0 xs
[0,1,3,6,10,15]
Trying to get this same behaviour seems unnecessarily troublesome in Rust.
let xs = [1, 2, 3, 4, 5];
let vs = vec![0]
.into_iter()
.chain(xs.iter().scan(0, |acc, x| {
*acc += x;
Some(*acc)
}))
.collect::<Vec<_>>();
The awkward scan behaviour of having to mutate the accumulator can be explained by a lack of GC. But, scan also does not include the initial accumulator value, necessitating the need to manually prepend a 0 at the front. This itself was troublesome, as I needed to prepend it with chain and [0].iter() didn't work, nor did [0].into_iter() and vec![0].iter(). It needed vec![0].into_iter().
I feel like I must be doing something wrong here. But, what? Is there a better way to generate a cumulative sum? Is it back to a for loop?
Edit :
Despite the old version of this answer mimics the behavior of scanl's intermediate form, the execution wasn't lazy. Updated the generic implementation from my old answer with #French Boiethios's answer.
This is the implementation :
fn scanl<'u, T, F>(op: F, initial: T, list: &'u [T]) -> impl Iterator<Item = T> + 'u
where
F: Fn(&T, &T) -> T + 'u,
{
let mut iter = list.iter();
std::iter::successors(Some(initial), move |acc| iter.next().map(|n| op(n, acc)))
}
//scanl(|x, y| x + y, 0, &[1, 2, 3, 4, 5]).collect::<Vec<_>>()
Playground
It can be easily implemented by a fold
For an Add operation:
let result = xs.iter().fold(vec![0], |mut acc, val| {
acc.push(val + acc.last().unwrap());
acc
});
Playground
Here is the generic version :
fn scanl<T, F>(op: F, initial: T, list: &[T]) -> Vec<T>
where
F: Fn(&T, &T) -> T,
{
let mut acc = Vec::with_capacity(list.len());
acc.push(initial);
list.iter().fold(acc, |mut acc, val| {
acc.push(op(val, acc.last().unwrap()));
acc
})
}
//scanl(|x, y| x + y, 0, &[1, 2, 3, 4, 5])
Playground
I would do that with successors:
fn main() {
let mut xs = vec![1, 2, 3, 4, 5].into_iter();
let vs = std::iter::successors(Some(0), |acc| xs.next().map(|n| n + *acc));
assert_eq!(vs.collect::<Vec<_>>(), [0, 1, 3, 6, 10, 15]);
}
The awkward scan behaviour of having to mutate the accumulator can be explained by a lack of GC.
There is nothing preventing Rust from doing what you ask.
Example of possible implementation:
pub struct Mapscan<I, A, F> {
accu: Option<A>,
iter: I,
f: F,
}
impl<I, A, F> Mapscan<I, A, F> {
pub fn new(iter: I, accu: Option<A>, f: F) -> Self {
Self { iter, accu, f }
}
}
impl<I, A, F> Iterator for Mapscan<I, A, F>
where
I: Iterator,
F: FnMut(&A, I::Item) -> Option<A>,
{
type Item = A;
fn next(&mut self) -> Option<Self::Item> {
self.accu.take().map(|accu| {
self.accu = self.iter.next().and_then(|item| (self.f)(&accu, item));
accu
})
}
}
trait IterPlus: Iterator {
fn map_scan<A, F>(self, accu: Option<A>, f: F) -> Mapscan<Self, A, F>
where
Self: Sized,
F: FnMut(&A, Self::Item) -> Option<A>,
{
Mapscan::new(self, accu, f)
}
}
impl<T: ?Sized> IterPlus for T where T: Iterator {}
fn main() {
let xs = [1, 2, 3, 4, 5];
let vs = xs
.iter()
.map_scan(Some(0), |acc, x| Some(acc + x));
assert_eq!(vs.collect::<Vec<_>>(), [0, 1, 3, 6, 10, 15]);
}
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 have a Vec<(A, B)> and I want to group by A but not just consecutive but all elements in the Vec. The closest thing I found is Itertools::group_by which only works on consecutive values. I understand that the consecutiveness is related to optimizing allocation but I just want a regular C# group by. Priority is to not have to use a new library just for this.
A is not hashable, only Ord. I want a resulting Vec<(A, Vec<(A, B))> or equivalent
Assuming that "comparable" means A: Ord, i.e. that there is a total ordering on A, you can fold an iterator over items of type (A, B) into a BTreeMap from A to Vec<B>:
use std::collections::BTreeMap;
fn group_pairs<A, B, I>(v: I) -> BTreeMap<A, Vec<B>>
where
A: Ord,
I: IntoIterator<Item = (A, B)>,
{
v.into_iter().fold(BTreeMap::new(), |mut acc, (a, b)| {
acc.entry(a).or_default().push(b);
acc
})
}
Some people prefer a for loop over a fold:
fn group_pairs<A, B, I>(v: I) -> BTreeMap<A, Vec<B>>
where
A: Ord,
I: IntoIterator<Item = (A, B)>,
{
let mut result = BTreeMap::<A, Vec<B>>::new();
for (a, b) in v {
result.entry(a).or_default().push(b);
}
result
}
Example:
let data = vec![(1, 2), (2, 3), (1, 1), (2, 4), (3, 5)];
let grouped = vec![(1, vec![2, 1]), (2, vec![3, 4]), (3, vec![5])];
assert_eq!(group_pairs(data).into_iter().collect::<Vec<_>>(), grouped);
(rust noob here; I'm trying to understand what can/cannot/should/shouldn't be passed by reference in a higher order function situation)
let a = [1, 2, 3];
This invocation works:
let sum = a.iter().fold(0, |acc: i32, x: &i32| acc + x);
These do not:
let sum = a.iter().fold(0, |acc: i32, x: i32| acc + x);
let sum = a.iter().fold(0, |acc: &i32, x: i32| acc + x);
The error message is
error[E0631]: type mismatch in closure arguments
--> main.rs:8:22
|
8 | let sum = a.iter().fold(0, |acc: &i32, x: i32| acc + x);
| ^^^^ --------------------------- found signature of `for<'r> fn(&'r i32, i32) -> _`
| |
| expected signature of `fn({integer}, &{integer}) -> _`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0631`.
The explanation does not offer anything of interest. It says the arguments of the closure do not match those of the arguments of fold. I however cannot see how it follows from the declaration of fold:
fn fold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B
Why is the second argument supposed to be &{integer}, and the first one {integer}?
The items in the iterator are borrowed from the array, so are &i32 not i32. This form works because the accumulator is owned, while the items are borrowed:
let sum = a.iter().fold(0, |acc: i32, x: &i32| acc + x);
You can convert the iterator so its items are copied instead of referenced, and then the first form will work:
let sum = a.iter().copied().fold(0, |acc: i32, x: i32| acc + x);
The third form can never work. The closure needs to be able to return a new value with which to update the accumulator. The type of the accumulator is i32. It can't be a reference because you can't return a reference from a closure (the original value would be dropped and Rust won't let you return a dangling pointer).
Looking at the declaration of fold()
fn fold<B, F>(self, init: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B
you can see that the function has two generic type parameters – the type of the accumulator B and the type of the closure F. The closure type has the trait bound FnMut(B, Self::Item) -> B, meaning that the type of the first argument is identical to the type of the accumulator, while the type of the second argument is the item type of the iterator.
In the invocation
let sum = a.iter().fold(0, |acc, x| acc + x);
we use an iterator with the item type &i32, and your accumulator is initialised to 0, so it's type is inferred to be i32 (which is the default integer type in the absence of any further qualification).
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
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.)