2012-01-03 35 views
13

Option不是Traversable有理由嗎?爲什麼選項不可穿過?

在斯卡拉2.9,Seq(Set(1,3,2),Seq(4),Option(5)).flatten不編譯,只是它實現Traversable特質接縫對我來說是合理的。如果不是這種情況,肯定會有一些我不認爲不允許的東西。它是什麼?

PS:當試圖去理解,我實現了編譯,就像可怕的事情:

scala> Seq(Set(1,3,2),Seq(4),Map("one"->1, 2->"two")).flatten 
res1: Seq[Any] = List(1, 3, 2, 4, (one,1), (2,two)) 

PS2:我知道我可以寫:Seq(Set(1,3,2),Seq(4),Option(5).toSeq).flatten或其它醜陋的東西。

PS3:有接縫要在最後一個月的工作,使Option看起來更像Traversable沒有實現它:commitanother commit

+2

對於語言(或在這種情況下的庫)設計這樣的問題,通常最好直接詢問語言(或庫)設計者。他們在郵件列表上相當敏感,但只是偶爾訪問StackOverflow。 – 2012-01-03 23:42:13

+4

@JörgWMittag這將是很高興有SO編譯答案,雖然.. – 2012-01-04 10:39:51

回答

5

圍繞flatMap返回Option而不是Traversable可能存在挑戰。儘管這在整個2.8 CanBuildFrom機器之前。

問題是asked曾經在郵件列表中,但沒有引起迴應。

這裏是一個例證:

sealed trait OptionX[+A] extends Traversable[A] { 
    def foreach[U](f: (A) => U): Unit = if (!isEmpty) f(get) 
    def get: A 
    def isDefined: Boolean 
    def getOrElse[B >: A](default: => B): B 
} 

case class SomeX[+A](a: A) extends OptionX[A] { 
    override def isEmpty = false 
    def get = a 
    def isDefined = true 
    def getOrElse[B >: A](default: => B) = a 
} 

case object NoneX extends OptionX[Nothing] { 
    override def isEmpty = true 
    def get = sys.error("none") 
    def isDefined = false 
    def getOrElse[B](default: => B) = default 
} 

object O extends App { 
    val s: OptionX[Int] = SomeX(1) 
    val n: OptionX[Int] = NoneX 
    s.foreach(i => println("some " + i)) 
    n.foreach(i => println("should not print " + i)) 
    println(s.map(_ + "!")) 
} 

最後一行返回的List("1!")代替Option。可能有人會想出一個CanBuildFrom這將產生SomeX("1!")。我的企圖沒有得逞:

object OptionX { 
    implicit def canBuildFrom[Elem] = new CanBuildFrom[Traversable[_], Elem, OptionX[Elem]] { 
    def builder() = new Builder[Elem, OptionX[Elem]] { 
     var current: OptionX[Elem] = NoneX 
     def +=(elem: Elem): this.type = { 
     if (current.isDefined) sys.error("already defined") 
     else current = SomeX(elem) 
     this 
     } 
     def clear() { current = NoneX } 
     def result(): OptionX[Elem] = current 
    } 
    def apply() = builder() 
    def apply(from: Traversable[_]) = builder() 
    } 
} 

我要明確地傳遞隱:

scala> import o._ 
import o._ 

scala> val s: OptionX[Int] = SomeX(1) 
s: o.OptionX[Int] = SomeX(1) 

scala> s.map(_+1)(OptionX.canBuildFrom[Int]) 
res1: o.OptionX[Int] = SomeX(2) 

scala> s.map(_+1) 
res2: Traversable[Int] = List(2) 

編輯:

所以,我是能夠解決的問題,並有SomeX(1).map(1+)返回OptionX通過OptionX延伸TraversableLike[A, OptionX[A]]和覆蓋newBuilder

但後來我得到運行時錯誤SomeX(1) ++ SomeX(2)for (i <- SomeX(1); j <- List(1,2)) yield (i+j)。所以我不認爲可以選擇延長Traversable,並且在返回最具體的類型方面做一些理智的事情。

除了可行性,編碼風格明智,我不確定在任何情況下Option的行爲如同Traversable都是好事。 Option代表並非總是定義的值,而Traversable定義了可以包含多個元素的集合的方法,如drop(n),splitAt(n),take(n),++。雖然如果Option也是Traversable會提供方便,但我認爲它可能使意圖不太清楚。

在必要時使用toSeq似乎是一種無痛的方式,表明我希望我的選項的行爲類似於Traversable。而對於某些重複使用的情況下,有option2Iterable隱式轉換 - 因此,例如這個已經工作(他們都返回List(1,2)):

  • List(Option(1), Option(2), None).flatten
  • for (i <- List(0,1); j <- Some(1)) yield (i+j)
  • Some(1) ++ Some(2)
+0

很好的答案,謝謝 – shellholic 2012-01-05 06:58:16

1

的原因是,在某些情況下implicits應用的類型會得到不太精確。你仍然會有一個Option的值,但是靜態返回類型可能類似於Iterable,e。 G。不是「最精確」的一個。

1

也許我很密集,但我不明白爲什麼有人會需要這個。此外,還需要NoneTraversable,這在語義上似乎是可疑的。

他們說設計完成時沒有什麼可以添加的東西,而是沒有東西可以帶走。當然,並不是說Scala標準庫是完美的。

+1

'無'是'Traversable' – shellholic 2012-01-04 23:38:38

+0

Touché。然而'無'和'無'意味着完全不同的東西。 'Nil'擴展'List [Nothing]'並且是List()的值。如果'Nil'不是'Traversable',會導致很多問題:) – 2012-01-06 19:51:41

+0

'Future.traverse(option)(f)'或'Future.sequence(option)'如何?我認爲你也可以同樣爭辯說,聖安德烈聖安佈雷的引述是支持'Option'是'Traversable'的論點。現在我們有一個「Traversable」是可以遍歷的東西,除了'Option'幾乎具有所有'Traversable'的行爲,但這不是一個,所以你應該有單獨的'選項'和其他各種收藏。「我們添加的東西是邏輯上不存在的任意區別。 – 2017-08-25 23:17:30

4

它不是Traversable,因爲您無法爲其實施scala.collection.mutable.Builder

那麼,它可能是一個Traversable,即使如此,但這會導致很多方法返回Option現在返回Traversable來代替。如果您想查看這些方法,請查看採用CanBuildFrom參數的方法。

讓我們把你的示例代碼來說明爲什麼:

Seq(Set(1,3,2),Seq(4),Option(5)).flatten 

這應該等於:

Seq(1, 2, 3, 4, 5) 

現在,讓我們考慮這個選擇:

Option(Set(1,3,2),Seq(4),Option(5)).flatten 

有什麼那個價值?

+2

'Option#apply'有一個參數,在這種情況下的答案是:'Option(Set(1,3,2))。flatten => Set(1,3,2)' – shellholic 2012-01-04 23:36:26

相關問題