简体   繁体   English

Scala更高级的kinded类型语法

[英]Scala higher kinded type syntax

I'm new to Scala and new to higher kinded types. 我是Scala的新手,也是更高级别的新手。 I want to write something like this; 我想写这样的东西;

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

However I can't refer to the type parameter Dependency in the execute method - the compiler doesn't know it. 但是我不能在execute方法中引用类型参数Dependency - 编译器不知道它。

I'm aware I can solve it in the following way without HKTs, but this isn't what this question is about; 我知道如果没有HKT,我可以通过以下方式解决它,但这不是这个问题的内容;

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

I'd like to understand why it doesn't work with the higher kinded type syntax that I've tried? 我想理解为什么它不适用于我尝试过的更高级的kinded类型语法? Is it possible at all to express this with HKTs? 是否有可能用HKT表达这一点? Is this a valid use-case for a HKT? 这是HKT的有效用例吗?


EDIT 编辑

A bit more information, Event looks like this; 更多信息,事件看起来像这样;

trait Event[Data] {
   val payload: Data
}

...and I'm looking to define an event and an actor like this; ......我正在寻找一个像这样的事件和演员;

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

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

I will try to improve Alexey's answer - he is right, but he is too short. 我会尽力改善阿列克谢的答案 - 他是对的,但他太矮了。 But I must say that I'm not an expert in HKT and I think I'm only starting to understand the concept. 但我必须说我不是HKT的专家,我想我才刚开始理解这个概念。

In your code E[Dependency] is the same as E[_] which says that you have E with some type as parameter. 在你的代码中, E[Dependency]E[_]相同,后者表示你有一些类型的E作为参数。 This means that you do not operate over Dependency as type. 这意味着您不会在Dependency操作类型。 You also do not operate over E or E[Dependency] as the type either. 您也不能使用EE[Dependency]作为类型。 E is a type constructor, and E[Dependency] is an existential type if I understood it correctly. E是一个类型构造函数,如果我理解正确, E[Dependency]是一个存在类型。 Please note that 请注意

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

or 要么

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

won't compile either. 也不会编译。

You need to specify the proper type as an argument for execute: 您需要指定正确的类型作为执行的参数:

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

This one will compile as E[B] is the type in this context. 这个将编译为E[B]是此上下文中的类型。

Updated: 更新:

Please take a look at this code: 请看一下这段代码:

  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)

Basically the trick is to define type P which is our Dependency and type E = Event[P] which is always Event[Dependency] then you can use the actor by defining P without defining E as it is already defined. 基本上诀窍是定义type P ,它是我们的Dependencytype E = Event[P] ,它总是Event[Dependency]然后你可以通过定义P而不定义E来使用actor,因为它已经定义了。 Not sure whether it solves the issue, but it looks like a way to go to me. 不确定它是否解决了这个问题,但它看起来像是一种方式去找我。 There are also too many types here, some like IntActor is not necessary. 这里也有太多类型,有些像IntActor是不必要的。 I've put them so it is easier to understand the example 我把它们放在一起,这样就更容易理解这个例子

However I can't refer to the type parameter Dependency in the execute method - the compiler doesn't know it. 但是我不能在execute方法中引用类型参数Dependency - 编译器不知道它。

You can't because it isn't a parameter of Actor . 你不能,因为它不是 Actor的参数。 Consider 考虑

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]?

UPDATE: Given your edit, the [Dependency, T <: Event[Dependency]] option is precisely what you need. 更新:鉴于您的编辑, [Dependency, T <: Event[Dependency]]选项正是您所需要的。 When you write Actor[E[Dependency] <: Event[Dependency]] , this means E itself has to have a type parameter. 当你编写Actor[E[Dependency] <: Event[Dependency]] ,这意味着E本身必须有一个类型参数。 And FooEvent doesn't, so Actor[FooEvent] won't compile. 并且FooEvent没有,所以Actor[FooEvent]不会编译。

UPDATE 2: You could try using type members as follows: 更新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) = {}
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM