From working on the first problem of the 99 Scala Puzzles I defined my own version of last
like so:
def last[A](xs: List[A]): A = xs match {
case x :: Nil => x
case x :: xs => last(xs)
}
My question is: Why is it necessary for last
to be directly followed by the type variable, as in last[A]
? Why couldn't the compiler just do the right thing if I wrote the function like so:
def last(xs: List[A]): A
.....
(leaving the [A]
off the end of last[A]
?)
And if the compiler is capable of figuring it out, then what is the rationale for designing the language this way?
I got an insight from @Lee's comment:
How would the compiler know that the A in List[A] doesn't refer to an actual type called A?
To demonstrate to myself that this made sense, I tried substituting the type variable A
, with the name of an actual type String
, and then passed the function a List[Int]
, seeing that when last
is declared like def last[String](xs: List[String]): String
, I was able to pass last
a List[Int]
:
scala> def last[String](xs: List[String]): String = xs match {
| case x :: Nil => x
| case x :: xs => last(xs)
| }
last: [String](xs: List[String])String
scala> last(List(1,2,3,4))
res7: Int = 4
Therefore proving the identifier String
does behave like a type variable, and does not reference the concrete type String
.
It would also make debugging more difficult if the compiler just assumed that any identifier not in scope was a type variable. It therefore, makes sense to have to declare it at the beginning of the function definition.