Scala更高级的kinded类型语法

时间:2015-09-26 20:27:21

标签: scala generics types higher-kinded-types

我是Scala的新手,也是更高级别的新手。我想写这样的东西;

trait Actor[E[Dependency] <: Event[Dependency]] {
  def execute(dependency: Dependency): Unit
}

但是我不能在execute方法中引用类型参数Dependency - 编译器不知道它。

我知道如果没有HKT,我可以通过以下方式解决它,但这不是这个问题的内容;

trait Actor[T <: Event[Dependency], Dependency] {
   def execute(dependency: Dependency): Unit
}

我想了解为什么它不适用于我尝试过的更高级的kinded类型语法?是否有可能用HKT表达这一点?这是HKT的有效用例吗?

修改

更多信息,事件看起来像这样;

trait Event[Data] {
   val payload: Data
}

...我想要定义一个事件和这样的演员;

case class FooEvent(payload: Foo) extends Event[Foo]

class FooActor extends Actor[FooEvent] {
   def execute(dependency: Foo) = {}
}

2 个答案:

答案 0 :(得分:2)

我会尽力改善阿列克谢的答案 - 他是对的,但他太矮了。但我必须说我不是HKT的专家,我想我才开始理解这个概念。

在您的代码E[Dependency]中,E[_]E相同,后者表示您将某些类型作为参数Dependency。这意味着您不会在E类型上运行。您也不能使用E[Dependency]E作为类型。 E[Dependency]是一个类型构造函数,如果我理解正确,trait Actor[E[D] <: Event[D]] { def execute(d: E) {} } 是一个存在类型。请注意

trait Actor[E[D] <: Event[D]] { def execute(d: E[D]) {} }

trait Actor[E[D] <: Event[D]] { def execute[B](d: E[B]) {} }

也不会编译。

您需要指定正确的类型作为执行的参数:

E[B]

这个将编译为 trait Event[P] { val payload: P } case class FooEvent(payload: Int) extends Event[Int] trait BaseActor { type E = Event[P] type P def execute(dep: P) def runEvent(event: E) } trait IntActor extends BaseActor { type P = Int } class FooActor extends IntActor { def execute(dependency: P) = {} def runEvent(event: E) = {} } val c = new FooActor() c.runEvent(FooEvent(5)) c.execute(5) 是此上下文中的类型。

<强>更新

请看一下这段代码:

type P

基本上诀窍是定义Dependencytype E = Event[P]Event[Dependency]始终是P,然后您可以通过定义E来使用actor定义IntActor,因为它已经定义。不确定它是否解决了这个问题,但它看起来像是一种方式去找我。这里也有太多类型,有些像abstract trait Abstract trait A extends Abstract trait B extends Abstract class C1 extends A class C2 extends A class C3 extends B class C4 extends B object NoCompile{ def foo(s: Abstract) = s match { case A => case B => } } [error] not found: value A [error] case A => [error] ^ [error] not found: value B [error] case B => 这样不必要。我把它们放在一起以便更容易理解这个例子

答案 1 :(得分:1)

  

但是我不能在execute方法中引用类型参数Dependency - 编译器不知道它。

你不能,因为不是 Actor的参数。考虑

val actor = new Actor[Event] // E is Event
actor.execute(???) // what argument is this supposed to take? I.e. what is Dependency for Actor[Event]?

更新:根据您的修改,[Dependency, T <: Event[Dependency]]选项正好您需要的内容。当您编写Actor[E[Dependency] <: Event[Dependency]]时,这意味着E本身必须具有类型参数。并且FooEvent没有,因此Actor[FooEvent]将无法编译。

更新2:您可以尝试使用类型成员,如下所示:

trait Event {
  type Dependency
  val payload: Dependency
}

trait Actor {
  type E <: Event

  def execute(e: E#Dependency)
}

class Foo

case class FooEvent(payload: Foo) extends Event {
  type Dependency = Foo
}

class FooActor extends Actor {
  type E = FooEvent

  def execute(e: Foo) = {}
}