In fact, there’s a strong case that the marker for a missing type argument should be “_
”. Note that after the current migration a “_
” in a type application will mean lambda abstraction, aligned with its meaning for term application. So Map[Int, _]
is [X] =>> Map[Int, X]
. Therefore, new Map[Int, _]
is a polymorphic function over the “value” parameter of Map
, and that type argument is inferred. This is analogous to new Map
being a polymorphic function with two inferred parameters, which are both inferred.
By analogy, f[A, _]
should also mean polymorphic lambda abstraction in function applications. So f[A, _]
means a polymorphic function in one argument, which is inferred. In fact, we could also allow to give it explicitly to be consistent. So
f[A, _][B] = f[A, B]
just like
f(a, _)(b) = f(a, b) // with the meaning of "reduces-to"
for terms.
I think things are falling into place now. If we have type lambda abstraction by means of “_
”, then named type arguments compose with that cleanly. Named arguments are re-ordered according to
the definition order and missing bindings are filled in with “_
”. E.g.
Map[V = String] = Map[_, String]
Subsequent type arguments can be inferred or given explicitly. Examples:
new Map[V = String](1 -> "a") // infers `K = Int`
or
new Map[V = String][Int]
A separate question is whether we want to allow curried type parameter definitions at definition site. I.e.
def f[A][B]
class Map[K][V]
instead of
def f[A, B]
class Map[K, V]
This will be very hard to do for classes, but it’s technically no problem for methods. However, as I said before, it would likely cause a split in the ecosystem how type parameterization is defined. So I think we should do this only once all the other discussed elements are settled, if at all.