2012-11-21 16 views
2

我想在Scala中使用foldLeft運算符連接一系列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) 

但是,如果我試圖用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,因爲我並不需要memoize的我所有的結果。

這可能看起來像一個奇怪的要求。 原因我想這樣做是因爲執行foldLeft而不是Traversable視圖提供了一種有效的方式來實現lazy depth first search

回答

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,而不是各種不同的意見。

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,但它是奇怪的類型(或者至少對我來說這種類型看起來很奇怪 - 也許有一個合理的解釋)。

在任何情況下,將您自己的適當類型的虛擬實例放入作用域中,至少現在是這樣。