这个例子来自于" 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()
的参数类型推断出类型参数。怎么了?我听说Product
和Serializable
会自动混合到案例类中,以便上面的函数文字类型为Int => Product with Serializable with A$A22.this.Maybe[_ <: Int]
,如错误消息所示。这与问题有关吗?
答案 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]
。