Confusion regarding placeholders for higher-kinded type lambdas

I keep hitting this wart where I expect to be able to use type lambdas with placeholders for higher kinded types, but I can never seem to make it work:

For context bounds, I would like to be able to write something like this:

def foo[F[_]: EitherT[*[_], String, Int] = ???

It seems like this case is simply not supported in Scala 3 at the moment?

I read this section Kind Projector Migration | Scala 3 Migration Guide | Scala Documentation from the docs, but the wording here is a bit difficult to decipher.

Is this use case going to be covered in the future, or do we have to explicitly write out the type lambdas for these cases?

I am not sure I understand what you want (which is probably a good reason not to have special syntax for this): Can you write down the type lambda you want *[_] to expand to?

It would be something like:

def foo[F[_]: [G[_]] =>> EitherT[G, String, Int]] = ???

which I personally find equally hard to read/understand. Not sure if it would be possible, but preferrably, I would love it if the compiler could just understand from the context that the placeholder needs to be higher kinded such that I could just write:

def foo[F[_]: EitherT[_, String, Int]] = ???

or * instead of the last instance of _. To be completely frank, the current situation is very confusing with the migration between the different placeholder syntaxes.

1 Like

G is not bound in the example. What’s its signature? EDIT: Sorry, I misread. It is hard to read for sure.

1 Like

I guess that means it’s not currently on the roadmap. Would this be a candidate for a SIP?

It can be proposed as a SIP. I am not sure it will fly though. My gut reaction would be that types like this are too complicated, and a complicated notation is a healthy pushback against going further down that road. I want to re-orient Scala with a radical focus on simplicity and that holds for the language as well as the libraries.

1 Like

One alternative here is to use a type alias that returns a type lambda, this works:

type EitherTC[A, B] = [F[_]] =>> EitherT[F, A, B]

def foo[F[_]: EitherTC[String, Int]] = ???

This can be generalized to arbitrary constructors of the same arity, but this might be getting too weird:

type TC[M[_[_], _, _]] = [A, B] =>> [F[_]] =>> M[F, A, B]

def foo[F[_]: TC[EitherT][String, Int]] = ???

Yeah, I explicitly wanted to be able to skip naming these :confused:

So, the plan of record is to eventually allow _ to be used in types to construct type lambda as described in Wildcard Arguments in Types (disregard the version numbers used in this document, they were only meant to give a vague idea of the timeline and need to be updated), I think it’d make sense for it to also work with higher-kinded arguments.

The trouble is that as long as people cross-compile with Scala 2, it’s hard to repurpose _. To help with this, I recently added support for ? in both 2.13 and 2.12 (https://github.com/scala/scala/pull/9990), but it will take a while before this becomes widespread. Meanwhile, it could make sense to implement the new meaning of _ under -source future. The current implementation of -Ykind-projector could serve as a basis for this, but it will need much more work.

1 Like