Proposal
Scala has always had anonymous functions or term lambdas:
(x: Int) => (x, x)
But there is no equivalent syntax for type lambdas, that is anonymous functions from type to type. The closest thing we can write in Scala today requires some creative use of various Scala features:
{type L[X] = (X,X)}#L
Needless to say, this isn’t ideal, so much so that the kind-projector compiler plugin was invented to provide a nicer syntax for this. Its popularity provides enough justification for addressing this directly in the language, therefore we’re proposing the following syntax, implemented in Dotty a couple of years ago already:
[X] => (X, X)
Internally, type lambdas are now a fundamental construct of the language and not just syntactic sugar, instead parameterized type definitions are now just sugar, that is:
type Foo[X] = (X, X)
is sugar for:
type Foo = [X] => (X, X)
Similarly, the existing:
def foo[M[X] <: Seq[X]]
Becomes sugar for:
def foo[M <: [X] => Seq[X]]
(which can also be abbreviated as def foo[M <: Seq]
)
For more details on how type lambdas behave see Type Lambdas - More Details
Open Questions
Curried type lambdas
Should we support currying for type lambdas ? That is, do we want the following to be legal:
type Foo = [X] => [Y] => (Y, X)
Foo[Int][String]
The current implementation in Dotty supports them, but I’m somewhat wary of that because we don’t have a good story for how this interacts with type inference, e.g.
def foo[M[_, _]](x: M[Int, Int])
we can only unify M
with a type constructor upper-bounded by [X, Y] => Any
(which might be conjured through partial unification), but inference isn’t going to uncurry or curry type lambdas by itself, so it won’t unify M
with a type constructor upper-bounded by [X] => [Y] => Any
.
Using underscores for type lambdas
I created a separate thread for this, let’s keep the discussion there since it does not directly impact this SIP: Pre-SIP: using underscores for type lambdas