2

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(_ ++ _)コンパイルされません。理由がわかりません。これについても説明していただければ幸いです。)

リストを頭と尾に分割して連結することもできます。

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)

しかし、同じことをIで行おうとすると、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を実装する効率的な方法が提供されるためです。

4

2 に答える 2

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オブジェクトはダミーのインスタンスを提供しますが、それは奇妙に型付けされています(または、少なくとも型は私には奇妙に思えます-おそらくそれについての合理的な説明があります)。

いずれにせよ、少なくとも今のところ、適切に型指定された独自のダミーインスタンスをスコープに配置することは機能します。

于 2012-11-21T19:31:34.380 に答える
3

ビューは、操作全体で含まれている要素のIDを維持しません++。これはバグだと確信しています。キャストすることで修正できます:

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、さまざまな異なるビューではなく、可能な限り使用するようにしています。

于 2012-11-21T19:08:28.960 に答える