Вопрос

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:

// error: not found: type S
def declare[A](fun: Impl[S] => Event[S, A] forSome { type S }): Key[A] = ???

...but it works when using the normal syntax:

// yes!
def declare[A](fun: Function1[Impl[S], Event[S, A]] forSome { type S }): Key[A] = ???

EDIT

Unfortunately, now my nice use site is screwed

missing parameter type for expanded function ((x$1) => x$1.renamed)
[error]    declare[ Renamed ]( _.renamed )

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 }...

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top