DEV Community

Sean Policarpio
Sean Policarpio

Posted on • Edited on

How to sequence in Rust

Well, I wouldn't say it's exactly the same sequencing in terms of FP languages like Scala et al., but it does the job for the given collection types in Rust; invert something of type F<G<A>> into G<F<A>>.

Usually, we'd expect F and G as types that are iterable and applicative. In the case of Rust, what I seem to understand from the standard library is that it is expected that there exists a trait implementation—FromIterator—that should allow G to be treated like an applicative. Since collect() is already iterating over a collection of G<A>, it's straightforward for an implementation of FromIterator for F to turn the results (i.e. a collection of them) of the first FromIterator into a G<F<A>>—which is what it does.

let opt = vec![Some(1), Some(2), Some(3)];
let sequenced = opt.into_iter().collect::<Option<Vec<i32>>>();
print!("{:?}", sequenced); // Some([1, 2, 3])

let opt = vec![Some(1), None, Some(3)];
let sequenced = opt.into_iter().collect::<Option<Vec<i32>>>();
print!("{:?}", sequenced); // None

let result = vec![Ok(1), Ok(2), Ok(3)];
let sequenced = result.into_iter().collect::<Result<Vec<i32>, &str>>();
print!("{:?}", sequenced); // Ok([1, 2, 3])

let result = vec![Ok(1), Err("oops"), Ok(3)];
let sequenced = result.into_iter().collect::<Result<Vec<i32>, &str>>();
print!("{:?}", sequenced); // Err("oops")

let result = vec![Ok(1), Ok(2), Ok(3)];
let sequenced = result.into_iter().map(|opt_i| opt_i.map(|i| i + 1)).collect::<Result<Vec<i32>, &str>>();
print!("{:?}", sequenced); // Ok([2, 3, 4])

originally posted as a gist.

Top comments (0)