scalagenericstype-inferencescala-generics

Scala type inference error


I wrote a combined map-and-find function that applies a function to an Iterable and returns the first mapped result for which a predicate is true:

implicit class EnhancedIterable[A, B[X] <: Iterable[X]](it: B[A]) {

  def mapAndFind[B](f: A => B, p: B => Boolean): Option[B] = {
    var result: Option[B] = None
    for (value <- it if result.isEmpty) {
      val r = f(value)
      if (p(r))
        result = Some(r)
    }
    result
  }

}

The problem is I hit a compilation error when I try to use the function as expected:

val names = Seq("Jose", "Chris", "Carlos", "Stephan")

names.mapAndFind(
  _.length,
  _ > 5 // Error
)

Type mismatch, expected: (NotInferedB) => Boolean, actual: (Nothing) => Any

If I use a type hint though things compile fine:

names.mapAndFind(
  _.length,
  (len: Int) => len > 5
)

Why is type B not inferred as Int from f?


Solution

  • Type inference in Scala flows between parameter lists, not inside them.

    You can write:

    implicit class EnhancedIterable[A, B[X] <: Iterable[X]](it: B[A]) {
      def mapAndFind[B](f: A => B)(p: B => Boolean): Option[B] = {
        var result: Option[B] = None
        for (value <- it if result.isEmpty) {
          val r = f(value)
          if (p(r)) result = Some(r)
        }
        result
      }
    }
    

    And then:

    val names = Seq("Jose", "Chris", "Carlos", "Stephan")
    names.mapAndFind(_.length)(_ > 5)
    

    Yields:

    Some(6)