This example is taken from an exercise of "Essential Scala" from Underscore.io.
Following is definition of algebraic sum type Maybe[A] which mimics some basic features of Option[A] and a list of 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))
I tried to replace the elements in list with odd values with Empty[Int] therefore resulting List(Empty(), Full(2), Empty()) by this statement:
list.map(maybe => maybe flatMap { x => if(x % 2 == 0) Full(x) else Empty() })
and this was the exactly same with the answer from the book.
But I got an error:
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() })
^
So I wrote type parameter then It worked well:
list.map(maybe => maybe flatMap[Int] { x => if(x % 2 == 0) Full(x) else Empty() })
I thought it would be ok even if I don't provide the type parameter Int because it seems that it was possible to infer the type parameter from the type of argument for flatMap x => if(x % 2 == 0) Full(x) else Empty(). What is wrong? I heard that Product and Serializable automatically mix-in into case class so that the type of the function literal above is Int => Product with Serializable with A$A22.this.Maybe[_ <: Int] as shown in the error message. Is this related to the issue?