Scala `view`:`force` 不是 `Seq` 的成员
Scala `view`: `force` is not a member of `Seq`
似乎应用 map
和 filter
以某种方式将 view
转换为 Seq
。 documentation 包含此示例:
> (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
是一个可变集合有关,因为我无法用 List
或 Vector
复制这种行为。但是,我可以 filter
Array
view
任意多次。
专业提示:在 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) => x.$plus(1)))(IndexedSeqView.arrCanBuildFrom).map(((x) => x.$times(2)))(Seq.canBuildFrom))
根据设计,IndexedSeqView.arrCanBuildFrom
不会生成另一个 IndexedSeqView
,而是生成一个普通的旧 SeqView
。但是,从那时起您希望 SeqView
s 保持不变。为了实现这一点,传递给第二个 map
的 CBF
应该是 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] <: Traversable[_]
。它就在那里。 Array
不是 Traversable
,所以它们在这里失败并被 Seq
中的 CBF
强制变成 Seq
。
要解决这个问题,SeqView
需要像 IndexedSeqView
那样有一个 arrCanBuildFrom
。这是库中的错误。这与 Array
可变无关;这真的是因为 Array
不是真正的集合(它没有实现 Traversable
)并且必须硬塞进去。
似乎应用 map
和 filter
以某种方式将 view
转换为 Seq
。 documentation 包含此示例:
> (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
是一个可变集合有关,因为我无法用 List
或 Vector
复制这种行为。但是,我可以 filter
Array
view
任意多次。
专业提示:在 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) => x.$plus(1)))(IndexedSeqView.arrCanBuildFrom).map(((x) => x.$times(2)))(Seq.canBuildFrom))
根据设计,IndexedSeqView.arrCanBuildFrom
不会生成另一个 IndexedSeqView
,而是生成一个普通的旧 SeqView
。但是,从那时起您希望 SeqView
s 保持不变。为了实现这一点,传递给第二个 map
的 CBF
应该是 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] <: Traversable[_]
。它就在那里。 Array
不是 Traversable
,所以它们在这里失败并被 Seq
中的 CBF
强制变成 Seq
。
要解决这个问题,SeqView
需要像 IndexedSeqView
那样有一个 arrCanBuildFrom
。这是库中的错误。这与 Array
可变无关;这真的是因为 Array
不是真正的集合(它没有实现 Traversable
)并且必须硬塞进去。