【发布时间】:2018-05-20 00:24:34
【问题描述】:
如果我想在 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);
}
产生这些错误:
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>(至少在概念上),但我希望我错了。
【问题讨论】:
-
盒装迭代器不能充分替代懒惰评估的 Haskell 变量,因为它不能倒带或克隆,因此这种直接翻译将不起作用。将列表表示为一串带框的
Chains 也不会有效。 -
@red75prime 好的,那么我该如何在通用和功能风格上做到这一点?
-
你正在写 Rust,但想到 Haskell,它会出错。看看this,看看 rust 实现会是什么样子。
-
@user1685095,您需要实现隐藏在引擎盖下的所有机器功能语言。我gave it a try.
-
我在reddit上发布了这个问题的链接,得到了非常有趣的答案:reddit.com/r/rust/comments/bdlna5/…
标签: rust cartesian-product generic-collections