Выражение ограниченного типа F как члена абстрактного типа

Я хочу преобразовать ограниченный 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)

Но возможно ли указать отношение в объявлении Подвижного признака? Если нет - почему?

Редактировать 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:

На вопрос не отвечает попытка смоделировать F-ограниченный полиморфизм как член типа в 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?

1 ответ

Тип-проекции в скале зависят от пути. Быстрый пример

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. Нет необходимости, чтобы х было таким же, как у.

Другие вопросы по тегам