Definicja funkcji może posiadać parametry typów w nawiasach kwadratowych [], oddzielonych przecinkiem. Deklaracja typów parametrów występuje po nazwie funkcji, a przed listą jej parametrów, np.

def flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): List[B]

W powyższym przykładzie metoda flatMap klasy scala.collection.immutable.List jest parametryzowana przez typ B.

Weźmy inna metodę

def iterate[A](start: A, len: Int)(f: (A) ⇒ A): List[A]

tym razem z obiektu scala.collection.immutable.List.

Czy patrząc na jej deklarację jesteś w stanie zrozumieć jej znaczenie? Czy do jej zrozumienia musisz znać typ A?

scala> import scala.collection.immutable.List._
import scala.collection.immutable.List._

scala> iterate(0, 5)(n => n + 1)
res0: List[Int] = List(0, 1, 2, 3, 4)

scala> iterate('a', 5)(c => (c.toInt + 1).toChar)
res1: List[Char] = List(a, b, c, d, e)

scala> iterate("a", 5)(s => s + s)
res2: List[String] = List(a, aa, aaaa, aaaaaaaa, aaaaaaaaaaaaaaaa)

Jak mogłaś zauważyć, kompilator Scali wydedukował typ dla A i w pierwszym przypadku był to Int, później Char, aby skończyć na String. Wciąż definicja funkcji iterate pozostała taka sama, a faktyczny typ miał mniejsze znaczenie (co nie oznacza, że nie miał znaczenia w ogóle).

Jest wiele funkcji, które nie tracą na swoim znaczeniu, kiedy typ parametrów jest podany (jawnie lub niejawnie) później i List.iterate jest tego dobrym przykładem.

Fork me on GitHub