从方法参数中推断方法的类型参数在Scala中失败?:"没有方法的类型参数"

时间:2017-08-17 21:36:00

标签: scala

这个例子来自于" Essential Scala"来自Underscore.io。 以下是代数和类型Maybe[A]的定义,它模仿Option[A]的一些基本特征和Maybe[Int]的列表。

sealed trait Maybe[A] {
  def flatMap[B](fn: A => Maybe[B]): Maybe[B] =
    this match {
      case Full(v) => fn(v)
      case Empty() => Empty[B]()
    }

  def map[B](fn: A => B): Maybe[B] =
    this match {
      case Full(v) => Full(fn(v))
      case Empty() => Empty[B]()
    }
}
final case class Full[A](value: A) extends Maybe[A]
final case class Empty[A]() extends Maybe[A]

val list = List(Full(3), Full(2), Full(1))

我尝试将list中的元素替换为具有空[Int]的奇数值,因此通过此语句生成List(Empty(), Full(2), Empty())

list.map(maybe => maybe flatMap { x => if(x % 2 == 0) Full(x) else Empty() })

这与本书的答案完全相同。

但我收到了一个错误:

Error:(41, 26) no type parameters for method flatMap: (fn: Int => A$A22.this.Maybe[B])A$A22.this.Maybe[B] exist so that it can be applied to arguments (Int => Product with Serializable with A$A22.this.Maybe[_ <: Int])
 --- because ---
argument expression's type is not compatible with formal parameter type;
 found   : Int => Product with Serializable with A$A22.this.Maybe[_ <: Int]
 required: Int => A$A22.this.Maybe[?B]
list.map(maybe => maybe flatMap { x => if(x % 2 == 0) Full(x) else Empty() })
                        ^

所以我写了类型参数然后它运作良好:

list.map(maybe => maybe flatMap[Int] { x => if(x % 2 == 0) Full(x) else Empty() })

我认为即使我没有提供类型参数Int也没关系,因为似乎可以从flatMap x => if(x % 2 == 0) Full(x) else Empty()的参数类型推断出类型参数。怎么了?我听说ProductSerializable会自动混合到案例类中,以便上面的函数文字类型为Int => Product with Serializable with A$A22.this.Maybe[_ <: Int],如错误消息所示。这与问题有关吗?

1 个答案:

答案 0 :(得分:1)

问题是Empty():除了Nothing之外,编译器没有理由为它选择任何类型参数(特别是,它没有查看if的其他分支)。因此,最终在一个分支中为Full[Int],在另一个分支中为Empty[Nothing],其常见类型为Product with Serializable with Maybe[_ <: Int],如错误消息所示。从结果类型,显然无法推断出flatMap的类型参数。

当定义一个只应按案例类扩展的特征时,包含trait Maybe[A] extends Product with Serializable是正常的,所以它们将被包含在这样的上限计算中,但你仍然会以Maybe[_ <: Int]结束(如果您不熟悉此表示法,则表示“Maybe其类型参数是Int”的某个子类型:编译器注意到Full[Int]是{{1}的子类型} Maybe[Int]Empty[Nothing]的子类型,但Maybe[Nothing]不是Maybe[Nothing]的子类型。

我希望您能在以下练习中找到解决问题的更好方法,但目前修复方法是指定Maybe[Int]