如何创建一个从迭代器的迭代器创建笛卡尔积Iterator的函数?

时间:2017-12-06 07:22:12

标签: rust generic-collections

如果我想在Haskell中创建列表列表的笛卡尔积,我可以这样做:

product [] = [[]]
product (xs:xss) = concatMap (\k -> map (k:) (product1 xss)) xs

甚至是这样:

sequence xss

我正在尝试实现一个在Rust中也会这样做的高效迭代器,但我不确定我的尝试有什么问题:

use std::iter::{empty, once};

fn product<T, I, V>(xss: I) -> Box<Iterator<Item = Iterator<Item = T>>>
where
    T: Clone,
    V: IntoIterator<Item = T>,
    I: IntoIterator<Item = V>,
{
    Box::new(xss.into_iter().fold(once(empty()), |acc, xs| {
        xs.into_iter().flat_map(|x| acc.map(|ys| ys.chain(once(x))))
    }))
}

fn main() {
    let data = vec![[1, 2, 3], [10, 20, 30], [100, 200, 300]];
    let it: Vec<Vec<u32>> = product(data).collect();
    println!("{:?}", it);
}

playground

产生以下错误:

error[E0308]: mismatched types
  --> src/main.rs:10:9
   |
10 |         xs.into_iter().flat_map(|x| acc.map(|ys| ys.chain(once(x))))
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::iter::Once`, found struct `std::iter::FlatMap`
   |
   = note: expected type `std::iter::Once<std::iter::Empty<T>>`
              found type `std::iter::FlatMap<<V as std::iter::IntoIterator>::IntoIter, std::iter::Map<std::iter::Once<std::iter::Empty<T>>, [closure@src/main.rs:10:45: 10:67 x:_]>, [closure@src/main.rs:10:33: 10:68 acc:_]>`

error[E0271]: type mismatch resolving `<std::iter::Once<std::iter::Empty<T>> as std::iter::Iterator>::Item == std::iter::Iterator<Item=T>`
  --> src/main.rs:9:5
   |
9  | /     Box::new(xss.into_iter().fold(once(empty()), |acc, xs| {
10 | |         xs.into_iter().flat_map(|x| acc.map(|ys| ys.chain(once(x))))
11 | |     }))
   | |_______^ expected struct `std::iter::Empty`, found trait std::iter::Iterator
   |
   = note: expected type `std::iter::Empty<T>`
              found type `std::iter::Iterator<Item=T>`
   = note: required for the cast to the object type `std::iter::Iterator<Item=std::iter::Iterator<Item=T>>`

error[E0277]: the trait bound `[{integer}; 3]: std::iter::Iterator` is not satisfied
  --> src/main.rs:16:29
   |
16 |     let it: Vec<Vec<u32>> = product(data).collect();
   |                             ^^^^^^^ `[{integer}; 3]` is not an iterator; maybe try calling `.iter()` or a similar method
   |
   = help: the trait `std::iter::Iterator` is not implemented for `[{integer}; 3]`
   = note: required because of the requirements on the impl of `std::iter::IntoIterator` for `[{integer}; 3]`
   = note: required by `product`

error: the `collect` method cannot be invoked on a trait object
  --> src/main.rs:16:43
   |
16 |     let it: Vec<Vec<u32>> = product(data).collect();
   |                                           ^^^^^^^

第一个错误让我感觉Rust甚至无法使用fold创建一个懒惰消耗的迭代器,因为Empty<T>Iterator<Item = T>(至少在概念上),但我希望我'我错了。

1 个答案:

答案 0 :(得分:0)

您的方法必然会失败的第一个原因是您尝试将设计用于列表的算法转换为处理迭代器的算法。列表适用于功能方法,迭代器不是,因为它们具有状态。 next(&mut self)函数每次使用相同的参数调用时都不会返回相同的值,而next(x:xs)函数则会返回相同的值。这就是implementation found in itertools克隆迭代器的原因:保存它们的初始状态并在集合上的下一次迭代中恢复它。

第二个原因是错误消息背后的原因是你正在与Rust的类型系统作斗争。您对迭代器函数(foldflat_map等)的所有调用的结果值都不是特征对象,而是具体类型&#39;。例如,iterator.fold(init, fn)的结果类型为init类型。这就是当你传递fold一个没有返回std::iter::Empty<T>的lambda时编译器抱怨的原因。

但它变得更糟。您可以设想将std::iter::Empty<T>强制或强制转换为特征对象。唉,需要物体安全。简而言之,"A good intuition is “except in special circumstances, if your trait’s method uses Self, it is not object-safe."。但是迭代器&#39;主要方法是next(&mut self)