Pregunta

After a lot of Java and some Haskell I wanted to have a look at Scala. From the code below, I'm getting this error message

type mismatch; found : List[Nothing] => Option[Nothing] required: List[Int] => Option[Nothing]

I don't know what I'm doing wrong:

object MyFirstScalaObject {

  def main(args: Array[String]) {
      lazy val testValues:List[List[Int]] = List((1 to 10).toList, null, List());

      println(  testFunction(last, testValues));
  }

  def testFunction[I, O](f : I => O, inputs : List[I]):
      List[(I, O)] = 
    inputs.zip(inputs.map(f));

  def last[A](xs:List[A]):Option[A] = xs match {
    case x::Nil => Some(x);
    case _::xs => last(xs);
    case _ => None;
  }

}

Thanks for any advice.

Cheers,

¿Fue útil?

Solución

because of the way type inference works in scala, it is unable to determine the what the type parameter to last has to be, so it has to take the overly conservative fallback guess that it is Nothing.

You can explicitly specify the types when you call testFunction:

testFunction[List[Int],Option[Int](last, testValues)

or you can document more fully the relationship between the type parameters in the testFunction declaration, which will give the type inferencer more information:

def testFunction[A, I[_], O[_]](f : I[A] => O[A], inputs : List[I[A]]): List[(I[A], O[A])]

This explicitly says that I and O are type constructors (kind * -> *), now that the input/output types of f are more specific, the inferencer can correctly infer that the A parameter to the the last function must be Int.

Otros consejos

A fully revised & tested version, using senia's idea:

object MyFirstScalaObject {
  def main(args: Array[String]) {
      lazy val testValues = List((1 to 10).toList, null, List())
      println(testFunction(testValues)(last))
  }

  def testFunction[I, O](inputs: List[I])(f: I => O): List[(I, O)] =
    inputs.zip(inputs.map(f))

  def last[A](xs: List[A]): Option[A] = xs match {
    case x :: Nil => Some(x)
    case _ :: xs => last(xs)
    case _ => None
  }
}

Type inference proceeds left-to-right; information from one parameter list is used within next parameter list. In this code, when you call testFunction Scala can deduce I from the first parameter, then it can feed I as the input type of the function f to figure out its type (that is, that the argument last is applied with A = Int), then it finally gets the value of O from the return type of the function.

I can't tell you why type inference in scala works this way.

But there is common way to help compiler in such cases - parameter sections.

def testFunction[I, O](inputs : List[I])(f: I => O): List[(I, O)] = inputs.zip(inputs.map(f))

Usage:

testFunction(testValues)(last)

Similar solution is to add method testFunction to class List:

class LastsHelper[T](inputs: List[T]) {
  def testFunction[O](f: T => O): List[(T, O)] = inputs.zip(inputs.map(f))
}
implicit def toLastsHelper[T](inputs: List[T]) = new LastsHelper(inputs)

You can use such methods like methods of List:

testValues.testFunction(last)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top