为什么选项不可穿越?

she*_*lic 15 collections scala

Option不存在是否合理Traversable

在Scala 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))
Run Code Online (Sandbox Code Playgroud)

PS2:我知道我可以写:Seq(Set(1,3,2),Seq(4),Option(5).toSeq).flatten或其他丑陋的东西.

PS3:在上个月有接缝工作,Option看起来更像是Traversable没有实现它:提交,另一个提交

huy*_*hjl 5

flatMap回归Option而不是回归可能会遇到挑战Traversable.虽然这比整个2.8 CanBuildFrom机器早.

这个问题曾经在邮件列表上被过一次,但没有得到答复.

这是一个例子:

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(_ + "!"))
}
Run Code Online (Sandbox Code Playgroud)

最后一行返回a 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()
  }
}
Run Code Online (Sandbox Code Playgroud)

我需要明确地传递隐式:

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)
Run Code Online (Sandbox Code Playgroud)

编辑:

所以我能够解决这个问题并通过扩展和覆盖来SomeX(1).map(1+)返回.OptionXOptionXTraversableLike[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)