scalatypeerrorscala-option

Type mismatch required: Option[Any] => Option[Nothing]


How can I fix this type error?

object Test extends App {
  def printOption[A](a: Option[A]): Option[A] = { println(a getOrElse("none")); a }

  def printHashCodeAndMap[A, B](fn: Option[A] => Option[B], list: List[Option[A]]): List[Option[B]] = {
    for (elem <- list) yield fn(elem.map{a => println(a.hashCode()); a})
  }

  val optListA = List(Some("aa"), None, Some(5))

  val optListB = printHashCodeAndMap(printOption, optListA)
  for (x <- optListB) printOption(x)
}

The error I get is:

error: type mismatch;
found   : Option[Nothing] => Option[Nothing]
required: Option[Any] => Option[Nothing]
val optListB = printHashCodeAndMap(printOption, optListA)

Solution

  • The problem is with how scala infers type parameters. Types information flows from left to right across parameter groups but not within the same parameter group.

    What that means is: the type parameter of printOption, A can be inferred only if A has been bound to a real type in a parameter group that precedes it's occurrence. In your printHashCodeAndMap, this is not the case. So, there are two ways to get this to work.

    i. You can forsake the type inference and explicitly specify the types of fn by passing it printOption[Any]. Or you could just specify the type parameters of printHashCodeAndMap when you call it (i.e. printHashCodeAndMap[Any, Any](printOption, optListA))

    ii. If you wanted to use scala's type inferrence, you'd want the type information for A to come from optListA which is of type List[Option[Any]]. To make that happen the parameter list has to be in a parameter group that precedes fn. Like this:

    def printHashCodeAndMap[A, B](list: List[Option[A]])(fn: Option[A] => Option[B]): List[Option[B]] = { ... }
    

    Then you will be able to call it like this:

    printHashCodeAndMap(optListA)(printOption)