7

我已经阅读了几篇文章,表示应该使用抽象类型来实现 Scala 中的 f 有界多态性。这主要是为了缓解类型推断问题,但也是为了消除在定义递归类型时类型参数似乎引入的二次增长。

这些定义如下:

trait EventSourced[E] {
  self =>

  type FBound <: EventSourced[E] { type FBound <: self.FBound }

  def apply(event: E): FBound
}

但是,这似乎引入了两个问题:

1) 每次用户想要引用该类型的对象时,他们还必须引用FBound类型参数。这感觉就像代码气味:

def mapToSomething[ES <: EventSourced[E], E](eventSourced: ES#FBound): Something[ES, E] = ...

2) 编译器现在无法推断上述方法的类型参数,失败并显示以下消息:

Type mismatch, expected: NotInferredES#FBound, actual: MyImpl#FBound

有没有人在他们的解决方案中成功实现了 f 有界多态性,从而编译器仍然能够推断类型?

4

3 回答 3

5

我已经意识到在大多数情况下应该避免 f 有界多态性 - 或者更确切地说 - 通常你应该选择另一种设计。要了解如何避免它,我们首先需要知道是什么让我们需要它:

当类型期望在派生类型中引入重要的接口更改时,就会发生 F 有界多态性。

这可以通过组合预期的更改区域而不是尝试通过继承来支持它们来避免。这实际上又回到了四人组设计模式:

偏爱“对象组合”而不是“类继承”

——(四人帮,1995)

例如:

trait Vehicle[V <: Vehicle[V, W], W] {
    def replaceWheels(wheels: W): V
}

变成:

trait Vehicle[T, W] {
    val vehicleType: T
    def replaceWheels(wheels: W): Vehicle[T, W]
}

这里,“预期变化”是车辆类型(例如BikeCarLorry)。前面的示例假设这将通过继承添加,需要一个 f 有界类型,这使得W使用 Vehicle 的任何函数都无法进行推断。使用组合的新方法不会出现这个问题。

请参阅:https ://github.com/ljwagerfield/scala-type-in​​ference/blob/master/README.md#avoiding-f-bounded-polymorphism

于 2016-09-14T12:29:04.503 回答
-1

请参阅Twitter 的 Scala School 中对 F 有界多态性的讨论。

于 2013-09-01T20:38:33.423 回答
-1

我可能在以下实现中遗漏了一些东西。

trait EventSourced[E] {
  self =>

  type FBound <: EventSourced[E] { type FBound <: self.FBound }

  def apply(event: E): FBound
}

trait Something[ES, E]

def mapToSomething[E](
  eventSourced: ES forSome {
    type ES <: EventSourced[E]
  }): Something[eventSourced.type, E] = ???

class Test extends EventSourced[Boolean] {
  type FBound = Test
  def apply(event:Boolean):FBound = ???
}

val x:Test  = ???

mapToSomething(x)
于 2014-02-17T16:45:21.070 回答