Question

I was trying to play around a bit with higher-kinds and type bounds when I bumped into this problem. My use case is that I want to be able to parameterize GenericAction instances with any subtype of Request, or the Request type itself. The Action trait extends the GenericAction trait with a default type of Request (in this case only anonymous instances of Request will be spawned).

trait Request[+A]

trait GenericAction[A, R[_] <: Request[_]]

trait Action[A] extends GenericAction[A, Request]

trait ActionBuilderBase[R[_] <: Request[_], G[_] <: GenericAction[_,R]]

ActionBuilderBase has utility methods that are shared with the sub-traits ActionBuilder and ActionBuilder2. ActionBuilder generates default Action[A] and Request[A] instances.

trait ActionBuilder extends ActionBuilderBase[Request,Action]

So far so good, but when I try to create another trait that extends ActionBuilderBase with a subtype of R and GenericAction (in this case anonymous instances of GenericAction would be created), it fails to compile. I guess the reason is that in the case of the first ActionBuilder, the request type has already been "filled in" (since Action[A] already has a request type == Request) , unlike the example below. What would I need to "fill in" in order for this example to work?

//Fails with "GenericAction takes two type parameters, expected: one" - what should the type annotation for GenericAction look like?
trait ActionBuilder2[R[_] <: Request[_]] extends ActionBuilderBase[R,GenericAction]
Was it helpful?

Solution

It would be nice in this situation to be able to write something like this:

trait ActionBuilder2[R[_] <: Request[_]] extends
  ActionBuilderBase[R, GenericAction[_, R]]

To indicate that you want to partially apply GenericAction. Unfortunately that's not valid Scala syntax (although Erik Osheim has a compiler plugin that lets you write something very similar).

You can use the "type lambda trick", however:

trait ActionBuilder2[R[_] <: Request[_]] extends
  ActionBuilderBase[R, ({ type L[A] = GenericAction[A, R] })#L]

See this answer for a detailed explanation of how it works.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top