6

我想将 F 有界多态性转换为抽象类型成员。

trait FBoundedMovable[Self <: FBoundedMovable[Self]] {
  def moveTo(pos: Vect2): Self
}

trait Movable { self =>
  type Self <: (Movable { type Self = self.Self })

  def moveTo(pos: Vect2): Self
}

到目前为止,一切都很好。

让我们定义一个实例:

case class Ship(pos: Vect2) extends Movable {
  type Self = Ship

  def moveTo(pos: Vect2) = copy(pos = pos)
}

并尝试使用它:

// [error]  found   : a.Self
// [error]  required: A
  def move[A <: Movable](a: A, to: Vect2): A = a.moveTo(to)

F 有界版本工作正常。

def moveF[A <: FBoundedMovable[A]](a: A, to: Vect2): A = a.moveTo(to)

我知道可以将类型边界添加到方法定义站点:

def move2[A <: Movable { type Self = A }](a: A, to: Vect2): A = a.moveTo(to)

但是是否可以在 Movable 特征声明中指定关系?如果不是 - 为什么?

编辑 1

我已经意识到我遇到了什么问题。

假设我们要声明某物是我们世界中的一个单位。

trait WorldUnit extends Movable with Damageable

所有单元都是可移动和可损坏的。

我们战斗计算的东西只关心那个东西Movable with Damagable。它不关心它是单元还是建筑物。

但是我们可以有这样的代码:

def doCombat(obj: Movable with Damagable) = obj.moveTo(...).takeDamage(...)
def doStuffWithUnit(obj: WorldUnit): WorldUnit = doCombat(obj) // and the type is lost here.

我注定要使用 F 有界类型吗?

编辑2:

Attempting to model F-bounded polymorphism as a type member in Scala没有回答这个问题——我之前已经尝试过,它丝毫不会影响返回类型,它仍然是 a.Self。

编辑3:

我找到了http://blog.jessitron.com/2014/02/when-oo-and-fp-meet-mytype-problem.html但问题仍未解决。

基本上,每当您有收藏并想挑选一个时:

(collection: Seq[Movable]).collectFirst { m: Movable if m.someCondition => m }- 您无法指定类型绑定,因此编译器无法证明 A#Self =:= A?

4

1 回答 1

3

scala中的类型投影是路径相关的。快速示例

scala> trait A{
     | type T
     | }
defined trait A

scala> val a = new A{type T = String}
a: A{type T = String} = $anon$1@31198ceb

scala> val b = new A{type T = String}
b: A{type T = String} = $anon$1@236ab296

scala> def f(implicit evidence: A =:= b.T) = null
f: (implicit evidence: =:=[A,b.T])Null

scala> f("asdf":a.T)
<console>:12: error: type mismatch;
 found   : a.T
    (which expands to)  String
 required: =:=[A,b.T]
    (which expands to)  =:=[A,String]
              f("asdf":a.T)
                      ^

在您的情况下,由于返回类型,它会引发错误。它正确地期待a.type,但你回来了A。而且它们不一样。

它们不应该相同的原因是: a.type返回一个类型<: Movable。对于想象,一些x小于 100 的数字。方法move返回A,对于想象,它是另一个y小于 100 的数字。x 不必与 y 相同。

于 2015-02-02T19:06:29.170 回答