Given some higher-kinded types:
trait Impl [S]
trait Event[S, A]
trait Key [A]
How can I rewrite the following definition:
def declare[A](fun: Impl[_] => Event[_, A]): Key[A] = ???
to constrain the fun
argument to actually be Impl[S] => Event[S, A]
for some S
. For example, in the following case:
trait Impl[S] { def ev1: Event[S, Int]; def ev2: Event[T, Int] }
This would be a valid call:
declare(_.ev1)
but this not:
declare(_.ev2) // this currently compiles
EDIT
Here comes a more complete example which shows exactly why I run into problems:
trait Sys [S <: Sys[S]]
trait Event[S <: Sys[S], A, Repr]
trait Decl {
type Impl[S <: Sys[S]]
protected def declare[U](fun: Impl[_] => Event[_, U, Impl[_]]): Unit = ???
}
The following event declaring companion object fails to compile:
object Test extends Decl {
type Impl[S <: Sys[S]] = Test[S]
case class Renamed(name: String)
declare[Renamed](_.renamed)
}
trait Test[S <: Sys[ S]] {
def renamed: Event[S, Test.Renamed, Test[S]]
}
due to some problem of matching types:
error: type mismatch;
found : Event[_$1,Test.Renamed,Test[_$1]] where type _$1
required: Event[_, Test.Renamed, Test.Impl[_]]
Note: _$1 <: Any, but trait Event is invariant in type S.
You may wish to define S as +S instead. (SLS 4.5)
Note: Test[_$1] <: Test[_], but trait Event is invariant in type Repr.
You may wish to define Repr as +Repr instead. (SLS 4.5)
declare[ Renamed ]( _.renamed )
^
If I change the function type to Impl[_] => Event[_, U, _]
it compiles, but I would really like to regain some type-safety.
The problem seems to be that the existential type cannot be given with the 'nice'
Function1
syntax:...but it works when using the normal syntax:
EDIT
Unfortunately, now my nice use site is screwed
So I have to stick with the type-unsafe version :-(
I guess I would need a new feature like
(Impl[S] => Event[S, A]) forAny { type S }
...