我正在尝试使用Traversable
运算符连接Scala中的一系列foldLeft
视图,并且遇到了我不理解的类型差异错误。
我可以使用reduce
来连接Traversable
视图列表。
val xs = List(1,2,3,4).map(Traversable(_).view).reduce((a: TraversableView[Int, Traversable[_]], b: TraversableView[Int, Traversable[_]]) => a ++ b) // TraversableView[Int,Traversable[_]]
// xs.force returns Traversable[Int] = List(1, 2, 3, 4)
(请注意,我必须在reduce
参数上编写类型注释:reduce(_ ++ _)
无法编译。我不明白为什么,也会感激对此的解释。)< / p>
我也可以将列表分成头部和尾部并将它们连接起来。
import collection.TraversableView
val ns = List(1,2,3,4)
val h = Traversable(ns.head).view
val t = ns.tail.map(Traversable(_).view).reduce((a: TraversableView[Int, Traversable[_]], b: TraversableView[Int, Traversable[_]]) => a ++ b)
val xs = h ++ t // TraversableView[Int,Traversable[_]]
// xs.force returns Traversable[Int] = List(1, 2, 3, 4)
但如果我尝试用foldLeft
做同样的事情,我会得到类型方差错误。
import collection.TraversableView
val ns = List(1,2,3,4)
val h = Traversable(ns.head).view
val t = ns.tail.map(Traversable(_).view)
val xs = (h /: t)((a: TraversableView[Int, Traversable[_]], b: TraversableView[Int, Traversable[_]]) => a ++ b)
<console>:14: error: type mismatch;
found : scala.collection.TraversableView[Int,Traversable[_]]
required: java.lang.Object with scala.collection.TraversableView[Int,Traversable[Int]]
(h /: t)((a: TraversableView[Int, Traversable[_]], b: TraversableView[Int, Traversable[_]]) => a ++ b)
我怀疑这个问题与Traversable[_]
中的存在主义类型有关,但我无法弄清楚我究竟做错了什么。我在上面的表达式中尝试了各种类型的签名无济于事。从Stackoverflow上的其他问题来看,foldLeft
的输入有些棘手,但我找不到解决这个问题的方法。
为了进行比较,使用Stream
的相同算法顺利运行。
val xs = (1 #:: Stream.empty /: List(2,3,4).map(_ #:: Stream.empty))(_ ++ _)
// xs.force returns Stream[Int] = Stream(1, 2, 3, 4)
以上是我想要做的,除了我想使用视图而不是Stream
,因为我不需要记住我的所有结果。
这似乎是一个奇怪的请求。 原因我想以这种方式执行操作是因为foldLeft
次Traversable
次视图提供了实现lazy depth first search的有效方法。
答案 0 :(得分:4)
这是一种解决方法(在2.9.2和2.10.0-RC2上测试):
import scala.collection.TraversableView
implicit def `I'm a lie!`[A]: collection.generic.CanBuildFrom[
TraversableView[A, Traversable[A]], A, TraversableView[A, Traversable[A]]
] = null
val xs = List(1, 2, 3, 4).map(Traversable(_).view).reduce(_ ++ _)
这两者都编译并做我们想要的事情:
scala> xs.toList
res0: List[Int] = List(1, 2, 3, 4)
即使使用(_ ++ _)
语法,左侧折叠版也可以使用。
问题是++
方法需要隐式CanBuildFrom
实例,但它实际上并不使用它。 TraversableView
对象提供了a dummy instance,但它是奇怪的类型(或者至少这种类型对我来说似乎很奇怪 - 也许对它有合理的解释)。
在任何情况下,将您自己的适当类型的虚拟实例放入范围工作,至少现在。
答案 1 :(得分:3)
视图不会在++
个操作中维护所包含元素的标识。我很确定这是一个错误。您可以通过强制转换来修复它:
val xs = List(1,2,3,4).map(Traversable(_).view).
reduce((a,b) => (a ++ b).asInstanceOf[TraversableView[Int,Traversable[Int]]])
在折叠案例中:
val xs = (Traversable(1).view /: List(2,3,4).map(x => Traversable(x).view)){ (l,r) =>
(l ++ r).asInstanceOf[TraversableView[Int,Traversable[Int]]]
}
但要小心!一旦你开始明确地投射,你的类型安全性就会下降(即由你决定不犯错误。)
我猜这是一种没有被大量使用的观点的症状。我通常会尽量使用Iterator
而不是各种不同的观点。