Monday, July 3, 2023

Rust closures ans iterators

 



Rust provides closures and iterators to enable functional programming. In first look it looks great, like the same nice functional programming in other programming languages, but a deeper check exposes that rust suffers from non friendly requirements. See the following example which demonstrates the weird iterators and closure interactions.



fn main() {
let mut updated_numbers: Vec<i32> = Vec::new();
let numbers = vec![1, 5, 4, 7, 8, 9];

// long and explicit definition of a closure
let decrement_number = |x: &i32| -> i32{
println!("decrement a number");
// here we access a variable from outside the closure scope
updated_numbers.push(x.clone());
x - 1
};

// short hand implicit definition of a closure
let increment_number = |x| x + 1;

// we use iterators to create new vectors
let incremented: Vec<i32> = numbers.iter().map(increment_number).collect();
let back_to_origin: Vec<i32> = incremented.iter().map(decrement_number).collect();


println!("numbers {:?}", numbers);
println!("incremented {:?}", incremented);
println!("and decremented back {:?}", back_to_origin);
println!("we've updated the following {:?}", updated_numbers);


/*
It turns out functional programming in rust is no fun!
iter() - creates a pointer to the items
filter() - creates another pointer to the pointer to the items
hence, we have a double pointer in the filter, very unexpected behavior
*/
let filter_even = |x: &&i32| -> bool { return *x % 2 == 0 };
let even: Vec<i32> = numbers.iter().filter(filter_even).map(|x: &i32| -> i32 { *x }).collect();

/*
This emphasise the complex rust internals.
we must redefine the closures since the order of actions is different
*/
let filter_even = |x: &i32| -> bool { return x % 2 == 0 };
let decrement_number = |x| x -1;
let odd: Vec<i32> = numbers.iter().map(increment_number).filter(filter_even).map(decrement_number).collect();

println!("even numbers are {:?}", even);
println!("odd numbers are {:?}", odd);
}




No comments:

Post a Comment