【问题标题】:Scala `view`: `force` is not a member of `Seq`Scala`view`:`force`不是`Seq`的成员
【发布时间】:2017-03-23 21:05:02
【问题描述】:

似乎应用mapfilter 以某种方式将view 转换为Seqdocumentation 包含此示例:

> (v.view map (_ + 1) map (_ * 2)).force
res12: Seq[Int] = Vector(4, 6, 8, 10, 12, 14, 16, 18, 20, 22)  

但是如果我做类似的事情,我会得到一个错误:

> val a = Array(1,2,3)
> s.view.map(_ + 1).map(_ + 1).force
<console>:67: error: value force is not a member of Seq[Int]

似乎如果我map 超过Array view 不止一次SeqView 变成Seq

> a.view.map(_+1)
res212: scala.collection.SeqView[Int,Array[Int]] = SeqViewM(...)
> a.view.map(_+1).map(_+1)
res211: Seq[Int] = SeqViewMM(...)

我怀疑这种行为可能与Array 是一个可变集合有关,因为我无法使用ListVector 复制这种行为。不过我可以filterArrayview 任意多次。

【问题讨论】:

  • 奇怪,看起来像 REPL 中的一个错误,因为我的 IDE 正确输入了这个。如果你能得到更多的反馈,也许你应该提交一个错误。
  • 使用 scala 的 IDE 我在尝试做a.view.map(_ + 1).map(_ + 1).force时遇到同样的错误@
  • 不过,它会让我在上面做.asInstanceOf[SeqView[Int, Array[Int]]].force 而不会抱怨。

标签: scala collections scala-collections


【解决方案1】:

专业提示:在 REPL 中调试隐式时,reflect 中的 reify 是你的朋友。

scala> import reflect.runtime.universe.reify
scala> import collection.mutable._ // To clean up reified exprs
scala> reify(a.view.map(_ + 1).map(_ * 2))
Expr[Seq[Int]](Predef.intArrayOps($read.a).view.map(((x$1) => x$1.$plus(1)))(IndexedSeqView.arrCanBuildFrom).map(((x$2) => x$2.$times(2)))(Seq.canBuildFrom))

按照设计,IndexedSeqView.arrCanBuildFrom 生成的不是另一个 IndexedSeqView,而是一个普通的旧 SeqView。但是,从那时起,您会期望SeqViews 保持这种状态。为了实现这一点,传递给第二个mapCBF 应该是SeqView.canBuildFrom,但出于某种原因,我们从Seq 获得了一个。现在我们知道了问题所在,让我们手动传递SeqView.canBuildFrom 并剖析错误。

scala> a.view.map(_ + 1).map(_ * 2)(collection.SeqView.canBuildFrom)
<console>:??: error: polymorphic expression cannot be instantiated to expected type;
 found   : [A]scala.collection.generic.CanBuildFrom[collection.SeqView.Coll,A,scala.collection.SeqView[A,Seq[_]]]
    (which expands to)  [A]scala.collection.generic.CanBuildFrom[scala.collection.TraversableView[_, _ <: Traversable[_]],A,scala.collection.SeqView[A,Seq[_]]]
 required: scala.collection.generic.CanBuildFrom[scala.collection.SeqView[Int,Array[Int]],Int,?]
       a.view.map(_ + 1).map(_ * 2)(collection.SeqView.canBuildFrom)
                                                       ^

好的,所以这不是隐式解析或编译器或任何东西的错误;是库出了问题,因为编译器能够给我们一个很好的理由让我们在这里失败。

scalac 要求CBF 的第二个类型参数是Int 或它的超类型,因为我们给它的参数是任何A,所以我们很好。第三个是未知的,所以它也可以是任何东西,也很好。因此,问题出在第一位。

scala> implicitly[collection.SeqView[Int, _] <:< collection.TraversableView[_, _]]
<function1>

这将问题缩小到Array[Int] &lt;: Traversable[_]。它就在那里。 Arrays 不是Traversable,所以他们在这里失败,并被Seq 中的CBF 强制变为Seqs。

要解决此问题,SeqView 需要像 IndexedSeqView 那样拥有 arrCanBuildFrom。这是库中的一个错误。这与 Array 的可变性无关;这真的是因为Array 不是真正的集合(它没有实现Traversable)并且必须硬塞进去。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-20
    • 1970-01-01
    • 1970-01-01
    • 2015-08-06
    • 1970-01-01
    • 2016-09-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多